Merge inbound to mozilla-central. a=merge
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Sat, 19 May 2018 12:39:28 +0300
changeset 419021 1d26b327ee6bcccdd7d3535cd5352a8ac3fb7d53
parent 419020 94e22944d8ea006c900dc0583c253113025dfef0 (current diff)
parent 418989 761d1da1d483d5573f91acd0d28082e90fbed28a (diff)
child 419022 7f19d8ef14c4d6c55764e8fa9c89421a244b0e57
child 419029 5fcd9707cd6c95d44a3d7b949a7aed97db4f3bb0
child 419031 3fc29973e494e07d71dae02d93348d185d68f675
push id103434
push userebalazs@mozilla.com
push dateSat, 19 May 2018 09:46:20 +0000
treeherdermozilla-inbound@7f19d8ef14c4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
1d26b327ee6b / 62.0a1 / 20180519100118 / files
nightly linux64
1d26b327ee6b / 62.0a1 / 20180519100118 / files
nightly mac
1d26b327ee6b / 62.0a1 / 20180519100118 / files
nightly win32
1d26b327ee6b / 62.0a1 / 20180519100118 / files
nightly win64
1d26b327ee6b / 62.0a1 / 20180519100118 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/CustomElementRegistry.cpp
testing/mozharness/configs/users/sfink/mock.py
testing/mozharness/mozharness/mozilla/mock.py
testing/mozharness/mozharness/mozilla/taskcluster_helper.py
testing/web-platform/tests/css/css-grid/reference/grid-collapsed-row-gutters-ref.html
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 55
+Version 56
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-54...release-55
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-55...release-56
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.2
 - babel-preset-react @6.24.1
 - react @16.2.0
 - react-dom @16.2.0
 - webpack @3.12.0
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -572,26 +572,25 @@ menuseparator {
 .refresh,
 .shortcut,
 .add-button {
   fill: var(--theme-splitter-color);
 }
 
 .folder,
 .domain,
-.source-icon,
 .file,
 .extension {
   background-color: var(--theme-comment);
 }
 
 .worker,
 .file,
 .folder,
-.source-icon,
+.sources-list .source-icon,
 .extension {
   position: relative;
   top: 2px;
 }
 
 .domain,
 .worker,
 .refresh,
@@ -603,18 +602,17 @@ menuseparator {
 .worker svg,
 .refresh svg,
 .shortcut svg,
 .add-button svg {
   width: 15px;
 }
 
 img.domain,
-img.folder,
-img.source-icon {
+img.folder {
   width: 15px;
   height: 15px;
 }
 
 img.extension {
   width: 13px;
   height: 13px;
   margin-inline-start: 2px;
@@ -661,17 +659,17 @@ img.file {
   mask: url("chrome://devtools/skin/images/debugger/file.svg") no-repeat;
   width: 13px;
   height: 13px;
 }
 
 img.domain,
 img.folder,
 img.file,
-img.source-icon,
+.sources-list img.source-icon,
 img.extension {
   mask-size: 100%;
   margin-inline-end: 5px;
   display: inline-block;
 }
 
 img.result-item-icon {
   mask-size: 100%;
@@ -1494,17 +1492,19 @@ html .toggle-button.end.vertical svg {
 .theme-dark .sources-list .managed-tree .tree .node img.blackBox {
   background-color: var(--theme-body-color);
 }
 
 .theme-dark .sources-list .managed-tree .tree .node.focused img.blackBox {
   background-color: white;
 }
 
-.tree:not(.object-inspector) .tree-node[data-expandable="false"] .tree-indent:last-of-type {
+.tree:not(.object-inspector)
+  .tree-node[data-expandable="false"]
+  .tree-indent:last-of-type {
   margin-inline-end: 4px;
 }
 
 /*
   Custom root styles
 */
 .sources-pane.sources-list-custom-root {
   display: block;
@@ -1520,17 +1520,19 @@ html .toggle-button.end.vertical svg {
   position: absolute;
   top: 26px;
   right: 0;
   bottom: 0;
   left: 0;
 }
 
 /* Removes start margin when a custom root is used */
-.sources-list-custom-root .tree > .tree-node[data-expandable="false"][aria-level="0"] {
+.sources-list-custom-root
+  .tree
+  > .tree-node[data-expandable="false"][aria-level="0"] {
   padding-inline-start: 4px;
 }
 /* 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/. */
 
 menu {
   display: inline;
@@ -1714,17 +1716,17 @@ menuseparator {
   -moz-user-select: none;
   user-select: none;
   height: 25px;
   box-sizing: border-box;
   display: flex;
 }
 
 .theme-dark .outline-footer button {
-    color: var(--theme-body-color);
+  color: var(--theme-body-color);
 }
 
 .outline-footer button.active {
   background: var(--theme-highlight-blue);
   color: #ffffff;
 }
 /* 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
@@ -2882,16 +2884,47 @@ debug-expression-error {
   margin-bottom: -1px;
 }
 
 .cm-highlight-full::before {
   border: 1px solid var(--theme-comment-alt);
   border-radius: 2px;
   margin: 0 -1px -1px -1px;
 }
+.source-icon {
+  position: relative;
+  background-color: var(--theme-comment);
+  mask-size: 100%;
+  display: inline-block;
+  margin-inline-end: 5px;
+}
+
+.source-icon,
+.source-icon svg {
+  width: 15px;
+  height: 15px;
+}
+
+.source-icon.prettyPrint {
+  mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat;
+  mask-size: 100%;
+  background: var(--theme-highlight-blue);
+  fill: var(--theme-textbox-box-shadow);
+}
+
+.source-icon.blackBox {
+  mask: url("chrome://devtools/skin/images/debugger/blackBox.svg") no-repeat;
+  mask-size: 100%;
+  background: var(--theme-highlight-blue);
+}
+
+.source-icon.react {
+  mask-size: 100%;
+  background: var(--theme-highlight-bluegrey);
+}
 /* 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/>. */
 
 .breakpoints-toggle {
   margin: 2px 3px;
 }
 
@@ -2901,17 +2934,24 @@ debug-expression-error {
 
 .breakpoints-list * {
   user-select: none;
 }
 
 .breakpoints-list .breakpoint-heading {
   text-overflow: ellipsis;
   overflow: hidden;
-  padding-top: 0.75em;
+  display: flex;
+  width: 100%;
+  align-items: center;
+}
+
+/* temporary until we refactor the sources tree and tab icon styles */
+.breakpoints-list .breakpoint-heading .source-icon.file {
+  top: 0;
 }
 
 .breakpoints-list .breakpoint-heading,
 .breakpoints-list .breakpoint {
   font-size: 12px;
   color: var(--theme-content-color1);
   position: relative;
   transition: all 0.25s ease;
@@ -2926,17 +2966,17 @@ debug-expression-error {
 }
 
 .breakpoints-exceptions {
   padding-bottom: 0.5em;
   padding-top: 0.5em;
 }
 
 .breakpoints-list .breakpoint {
- height: var(--breakpoint-expression-height);
+  min-height: var(--breakpoint-expression-height);
 }
 
 .breakpoints-exceptions-caught {
   padding: 0 1em 0.5em 3em;
   margin-top: -0.25em;
 }
 
 html[dir="rtl"] .breakpoints-exceptions-caught {
@@ -3188,33 +3228,33 @@ html[dir="rtl"] .breakpoints-list .break
 .expression-container {
   border: 1px;
   padding: 0.6em 1em 0.6em 0.5em;
   width: 100%;
   color: var(--theme-body-color);
   background-color: var(--theme-body-background);
   display: block;
   position: relative;
-  height: var(--breakpoint-expression-height);
+  min-height: var(--breakpoint-expression-height);
 }
 
 .expression-container > .tree {
   width: 100%;
   overflow: hidden;
 }
 
 :root.theme-light .expression-container:hover {
   background-color: var(--theme-selection-background-hover);
 }
 
 :root.theme-dark .expression-container:hover {
   background-color: var(--theme-selection-background-hover);
 }
 
-.tree  .tree-node:not(.focused):hover {
+.tree .tree-node:not(.focused):hover {
   background-color: transparent;
 }
 
 .expression-container__close-btn {
   position: absolute;
   offset-inline-end: 0px;
   top: 0px;
 }
@@ -3708,17 +3748,17 @@ img.skipPausing {
 }
 
 .command-bar .skipPausing {
   mask: url("chrome://devtools/skin/images/debugger/disable-pausing.svg") no-repeat;
   mask-size: 100%;
 }
 
 .command-bar .active .skipPausing {
-   background-color: var(--theme-highlight-blue);
+  background-color: var(--theme-highlight-blue);
 }
 
 .bottom {
   border-bottom: none;
   background-color: var(--theme-body-background);
   border-top: 1px solid var(--theme-splitter-color);
   flex: 0 0 25px;
 }
@@ -3744,16 +3784,24 @@ img.skipPausing {
 /* 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/>. */
 
 .object-node.default-property {
   opacity: 0.6;
 }
 
+.object-node {
+  padding-left: 4px;
+}
+
+html[dir="rtl"] .object-node {
+  padding-right: 4px;
+}
+
 .object-label {
   color: var(--theme-highlight-blue);
 }
 
 .objectBox-object,
 .objectBox-string,
 .objectBox-text,
 .objectBox-table,
@@ -3767,20 +3815,16 @@ img.skipPausing {
 .theme-light .objectBox-object {
   white-space: nowrap;
 }
 
 .scopes-pane {
   overflow: auto;
 }
 
-.scopes-list {
-  padding-inline-start: 4px;
-}
-
 .scopes-list .tree:focus {
   outline: none;
 }
 
 .scopes-list .function-signature {
   display: inline-block;
 }
 
@@ -3801,18 +3845,18 @@ img.skipPausing {
 .secondary-panes {
   overflow: auto;
   display: flex;
   flex-direction: column;
   flex: 1;
   white-space: nowrap;
   -moz-user-select: none;
   user-select: none;
- --breakpoint-expression-right-clear-space: 36px;
- --breakpoint-expression-height: 2.4em;
+  --breakpoint-expression-right-clear-space: 36px;
+  --breakpoint-expression-height: 2.4em;
 }
 
 /*
   We apply overflow to the container with the commandbar.
   This allows the commandbar to remain fixed when scrolling
   until the content completely ends. Not just the height of
   the wrapper.
   Ref: https://github.com/devtools-html/debugger.html/issues/3426
@@ -4024,50 +4068,38 @@ html .welcomebox .toggle-button-end.coll
   border-bottom-color: transparent;
 }
 
 .source-tab.active path,
 .source-tab:hover path {
   fill: var(--theme-body-color);
 }
 
-.source-tab img.prettyPrint {
-  mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat;
-  mask-size: 100%;
-  padding-top: 12px;
+.source-tab .source-icon {
+  margin-inline-end: 0;
+}
+
+.source-tab img.prettyPrint,
+.source-tab .source-icon.blackBox {
   height: 12px;
   width: 12px;
-  background: var(--theme-highlight-blue);
+  align-self: center;
 }
 
 .source-tab .prettyPrint path {
   fill: var(--theme-textbox-box-shadow);
 }
 
-.source-tab .blackBox,
-.source-tab .prettyPrint {
-  align-self: center;
-}
-
-.source-tab img.blackBox {
-  mask: url("chrome://devtools/skin/images/debugger/blackBox.svg") no-repeat;
-  mask-size: 100%;
-  padding-top: 12px;
-  height: 12px;
-  width: 12px;
-  background: var(--theme-highlight-blue);
-}
-
 .source-tab img.react {
   mask: url("chrome://devtools/skin/images/debugger/react.svg") no-repeat;
   mask-size: 100%;
-  padding-top: 12px;
   height: 14px;
   width: 14px;
   background: var(--theme-highlight-bluegrey);
+  top: 0;
 }
 
 .source-tab .blackBox path {
   fill: var(--theme-textbox-box-shadow);
 }
 
 .theme-dark .source-tab .blackBox circle {
   fill: var(--theme-body-color);
@@ -4088,17 +4120,17 @@ html[dir="rtl"] img.moreTabs {
   margin-right: 6px;
 }
 
 .source-tab .filename {
   white-space: nowrap;
   text-overflow: ellipsis;
   overflow: hidden;
   padding: 0 4px;
-  align-self: flex-start;
+  align-self: center;
 }
 
 .source-tab .close-btn {
   visibility: hidden;
   line-height: 0;
 }
 
 .source-tab.active .close-btn {
@@ -4182,17 +4214,16 @@ html[dir="rtl"] .dropdown {
   mask-size: 100%;
   background: var(--theme-highlight-blue);
 }
 
 .dropdown-icon.file {
   mask: url("chrome://devtools/skin/images/debugger/file.svg") no-repeat;
   mask-size: 100%;
   margin-bottom: 7px;
-
 }
 
 .dropdown ul {
   list-style: none;
   line-height: 2em;
   font-size: 1em;
   margin: 0;
   padding: 0;
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -25000,17 +25000,19 @@ function mapOriginalExpression(expressio
 
 const {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId
 } = __webpack_require__(3652);
 
-const { workerUtils: { WorkerDispatcher } } = __webpack_require__(3651);
+const {
+  workerUtils: { WorkerDispatcher }
+} = __webpack_require__(3651);
 
 const dispatcher = new WorkerDispatcher();
 
 const getOriginalURLs = dispatcher.task("getOriginalURLs");
 const getGeneratedRanges = dispatcher.task("getGeneratedRanges", {
   queue: true
 });
 const getGeneratedLocation = dispatcher.task("getGeneratedLocation", {
--- a/devtools/client/debugger/new/dist/vendors.css
+++ b/devtools/client/debugger/new/dist/vendors.css
@@ -95,26 +95,25 @@
 .refresh,
 .shortcut,
 .add-button {
   fill: var(--theme-splitter-color);
 }
 
 .folder,
 .domain,
-.source-icon,
 .file,
 .extension {
   background-color: var(--theme-comment);
 }
 
 .worker,
 .file,
 .folder,
-.source-icon,
+.sources-list .source-icon,
 .extension {
   position: relative;
   top: 2px;
 }
 
 .domain,
 .worker,
 .refresh,
@@ -126,18 +125,17 @@
 .worker svg,
 .refresh svg,
 .shortcut svg,
 .add-button svg {
   width: 15px;
 }
 
 img.domain,
-img.folder,
-img.source-icon {
+img.folder {
   width: 15px;
   height: 15px;
 }
 
 img.extension {
   width: 13px;
   height: 13px;
   margin-inline-start: 2px;
@@ -184,17 +182,17 @@ img.file {
   mask: url("chrome://devtools/skin/images/debugger/file.svg") no-repeat;
   width: 13px;
   height: 13px;
 }
 
 img.domain,
 img.folder,
 img.file,
-img.source-icon,
+.sources-list img.source-icon,
 img.extension {
   mask-size: 100%;
   margin-inline-end: 5px;
   display: inline-block;
 }
 
 img.result-item-icon {
   mask-size: 100%;
--- a/devtools/client/debugger/new/src/actions/preview.js
+++ b/devtools/client/debugger/new/src/actions/preview.js
@@ -89,17 +89,17 @@ function updatePreview(target, editor) {
     let match;
 
     if (!symbols || symbols.loading) {
       match = (0, _getExpression.getExpressionFromCoords)(editor.codeMirror, tokenPos);
     } else {
       match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
     }
 
-    if (!match || !match.expression) {
+    if (!match) {
       return;
     }
 
     const {
       expression,
       location
     } = match;
 
--- a/devtools/client/debugger/new/src/actions/utils/middleware/log.js
+++ b/devtools/client/debugger/new/src/actions/utils/middleware/log.js
@@ -6,17 +6,17 @@ Object.defineProperty(exports, "__esModu
 exports.log = log;
 
 var _devtoolsEnvironment = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-environment"];
 
 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
 
 function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
 
-const blacklist = ["SET_POPUP_OBJECT_PROPERTIES", "SET_PAUSE_POINTS", "SET_SYMBOLS", "OUT_OF_SCOPE_LOCATIONS", "MAP_SCOPES", "MAP_FRAMES", "ADD_SCOPES", "IN_SCOPE_LINES", "REMOVE_BREAKPOINT", "ADD_BREAKPOINT"];
+const blacklist = ["SET_POPUP_OBJECT_PROPERTIES", "SET_PAUSE_POINTS", "SET_SYMBOLS", "OUT_OF_SCOPE_LOCATIONS", "MAP_SCOPES", "MAP_FRAMES", "ADD_SCOPES", "IN_SCOPE_LINES", "REMOVE_BREAKPOINT"];
 
 function cloneAction(action) {
   action = action || {};
   action = _objectSpread({}, action); // ADD_TAB, ...
 
   if (action.source && action.source.text) {
     const source = _objectSpread({}, action.source, {
       text: ""
--- a/devtools/client/debugger/new/src/components/Editor/ConditionalPanel.js
+++ b/devtools/client/debugger/new/src/components/Editor/ConditionalPanel.js
@@ -101,16 +101,20 @@ class ConditionalPanel extends _react.Pu
   componentWillUpdate(nextProps) {
     if (nextProps.line) {
       return this.renderToWidget(nextProps);
     }
 
     return this.clearConditionalPanel();
   }
 
+  componentDidUpdate(prevProps) {
+    this.keepFocusOnInput();
+  }
+
   componentWillUnmount() {
     // This is called if CodeMirror is re-initializing itself before the
     // user closes the conditional panel. Clear the widget, and re-render it
     // as soon as this component gets remounted
     return this.clearConditionalPanel();
   }
 
   renderToWidget(props) {
@@ -145,18 +149,16 @@ class ConditionalPanel extends _react.Pu
 
         parent = parent.parentNode;
       }
 
       if (this.scrollParent) {
         this.scrollParent.addEventListener("scroll", this.repositionOnScroll);
         this.repositionOnScroll();
       }
-
-      this.input.focus();
     }
   }
 
   renderConditionalPanel(props) {
     const {
       breakpoint
     } = props;
     const condition = breakpoint ? breakpoint.condition : "";
--- a/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js
+++ b/devtools/client/debugger/new/src/components/Editor/Preview/Popup.js
@@ -178,17 +178,17 @@ class Popup extends _react.Component {
       onClick: () => selectSourceURL(location.url, {
         line: location.line
       })
     }, _react2.default.createElement(_PreviewFunction2.default, {
       func: value
     }));
   }
 
-  renderReact(react, roots) {
+  renderReact(react) {
     const reactHeader = react.displayName || "React Component";
     return _react2.default.createElement("div", {
       className: "header-container"
     }, _react2.default.createElement(_Svg2.default, {
       name: "react",
       className: "logo"
     }), _react2.default.createElement("h3", null, reactHeader));
   }
@@ -259,29 +259,29 @@ class Popup extends _react.Component {
       disableWrap: true,
       focusable: false,
       openLink: openLink,
       createObjectClient: grip => (0, _firefox.createObjectClient)(grip)
     });
   }
 
   renderPreview() {
+    // We don't have to check and
+    // return on `false`, `""`, `0`, `undefined` etc,
+    // these falsy simple typed value because we want to
+    // do `renderSimplePreview` on these values below.
     const {
       value
     } = this.props;
 
-    if (!value) {
-      return null;
-    }
-
-    if (value.class === "Function") {
+    if (value && value.class === "Function") {
       return this.renderFunctionPreview();
     }
 
-    if (value.type === "object") {
+    if (value && value.type === "object") {
       return _react2.default.createElement("div", null, this.renderObjectPreview());
     }
 
     return this.renderSimplePreview(value);
   }
 
   getPreviewType(value) {
     if (typeof value == "number" || typeof value == "boolean" || typeof value == "string" && value.length < 10 || typeof value == "number" && value.toString().length < 10 || value.type == "null" || value.type == "undefined" || value.class === "Function") {
--- a/devtools/client/debugger/new/src/components/Editor/Tab.js
+++ b/devtools/client/debugger/new/src/components/Editor/Tab.js
@@ -7,16 +7,20 @@ Object.defineProperty(exports, "__esModu
 var _react = require("devtools/client/shared/vendor/react");
 
 var _react2 = _interopRequireDefault(_react);
 
 var _reactRedux = require("devtools/client/shared/vendor/react-redux");
 
 var _devtoolsContextmenu = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-contextmenu"];
 
+var _SourceIcon = require("../shared/SourceIcon");
+
+var _SourceIcon2 = _interopRequireDefault(_SourceIcon);
+
 var _Button = require("../shared/Button/index");
 
 var _actions = require("../../actions/index");
 
 var _actions2 = _interopRequireDefault(_actions);
 
 var _source = require("../../utils/source");
 
@@ -126,25 +130,23 @@ class Tab extends _react.PureComponent {
     return this.props.activeSearch === "source";
   }
 
   render() {
     const {
       selectedSource,
       selectSpecificSource,
       closeTab,
-      source,
-      sourceMetaData
+      source
     } = this.props;
     const src = source.toJS();
     const filename = (0, _source.getFilename)(src);
     const sourceId = source.id;
     const active = selectedSource && sourceId == selectedSource.get("id") && !this.isProjectSearchEnabled() && !this.isSourceSearchEnabled();
     const isPrettyCode = (0, _source.isPretty)(source);
-    const sourceAnnotation = (0, _tabs.getSourceAnnotation)(source, sourceMetaData);
 
     function onClickClose(e) {
       e.stopPropagation();
       closeTab(source.url);
     }
 
     function handleTabClick(e) {
       e.preventDefault();
@@ -162,31 +164,33 @@ class Tab extends _react.PureComponent {
       pretty: isPrettyCode
     });
     return _react2.default.createElement("div", {
       className: className,
       key: sourceId,
       onMouseUp: handleTabClick,
       onContextMenu: e => this.onTabContextMenu(e, sourceId),
       title: (0, _source.getFileURL)(src)
-    }, sourceAnnotation, _react2.default.createElement("div", {
+    }, _react2.default.createElement(_SourceIcon2.default, {
+      source: source,
+      shouldHide: icon => ["file", "javascript"].includes(icon)
+    }), _react2.default.createElement("div", {
       className: "filename"
     }, filename), _react2.default.createElement(_Button.CloseButton, {
       handleClick: onClickClose,
       tooltip: L10N.getStr("sourceTabs.closeTabButtonTooltip")
     }));
   }
 
 }
 
 const mapStateToProps = (state, {
   source
 }) => {
   const selectedSource = (0, _selectors.getSelectedSource)(state);
   return {
     tabSources: (0, _selectors.getSourcesForTabs)(state),
     selectedSource: selectedSource,
-    sourceMetaData: (0, _selectors.getSourceMetaData)(state, source.id),
     activeSearch: (0, _selectors.getActiveSearch)(state)
   };
 };
 
 exports.default = (0, _reactRedux.connect)(mapStateToProps, _actions2.default)(Tab);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints.js
@@ -21,16 +21,20 @@ var I = _interopRequireWildcard(_immutab
 var _reselect = require("devtools/client/debugger/new/dist/vendors").vendored["reselect"];
 
 var _lodash = require("devtools/client/shared/vendor/lodash");
 
 var _Breakpoint = require("./Breakpoint");
 
 var _Breakpoint2 = _interopRequireDefault(_Breakpoint);
 
+var _SourceIcon = require("../shared/SourceIcon");
+
+var _SourceIcon2 = _interopRequireDefault(_SourceIcon);
+
 var _actions = require("../../actions/index");
 
 var _actions2 = _interopRequireDefault(_actions);
 
 var _source = require("../../utils/source");
 
 var _selectors = require("../../selectors/index");
 
@@ -131,17 +135,17 @@ class Breakpoints extends _react.Compone
   renderExceptionsOptions() {
     const {
       breakpoints,
       shouldPauseOnExceptions,
       shouldPauseOnCaughtExceptions,
       pauseOnExceptions
     } = this.props;
     const isEmpty = breakpoints.size == 0;
-    const exceptionsBox = createExceptionOption(L10N.getStr("pauseOnExceptionsItem2"), shouldPauseOnExceptions, () => pauseOnExceptions(!shouldPauseOnExceptions, false), "breakpoints-exceptions");
+    const exceptionsBox = createExceptionOption(L10N.getStr("pauseOnExceptionsItem"), shouldPauseOnExceptions, () => pauseOnExceptions(!shouldPauseOnExceptions, false), "breakpoints-exceptions");
     const ignoreCaughtBox = createExceptionOption(L10N.getStr("pauseOnCaughtExceptionsItem"), shouldPauseOnCaughtExceptions, () => pauseOnExceptions(true, !shouldPauseOnCaughtExceptions), "breakpoints-exceptions-caught");
     return _react2.default.createElement("div", {
       className: (0, _classnames2.default)("breakpoints-exceptions-options", {
         empty: isEmpty
       })
     }, exceptionsBox, shouldPauseOnExceptions ? ignoreCaughtBox : null);
   }
 
@@ -165,17 +169,19 @@ class Breakpoints extends _react.Compone
       const {
         source
       } = groupBreakpoints[0];
       return [_react2.default.createElement("div", {
         className: "breakpoint-heading",
         title: url,
         key: url,
         onClick: () => this.props.selectSource(source.id)
-      }, (0, _source.getFilename)(source)), ...groupBreakpoints.map(bp => this.renderBreakpoint(bp))];
+      }, _react2.default.createElement(_SourceIcon2.default, {
+        source: source
+      }), (0, _source.getFilename)(source)), ...groupBreakpoints.map(bp => this.renderBreakpoint(bp))];
     })];
   }
 
   render() {
     return _react2.default.createElement("div", {
       className: "pane breakpoints-list"
     }, this.renderExceptionsOptions(), this.renderBreakpoints());
   }
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js
@@ -130,16 +130,17 @@ class Expressions extends _react.Compone
         path: input,
         contents: {
           value
         }
       };
       return _react2.default.createElement("li", {
         className: "expression-container",
         key: input,
+        title: expression.input,
         onDoubleClick: (items, options) => this.editExpression(expression, index)
       }, _react2.default.createElement("div", {
         className: "expression-content"
       }, _react2.default.createElement(_devtoolsReps.ObjectInspector, {
         roots: [root],
         autoExpandDepth: 0,
         disableWrap: true,
         focusable: false,
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/components/shared/SourceIcon.js
@@ -0,0 +1,46 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _react = require("devtools/client/shared/vendor/react");
+
+var _react2 = _interopRequireDefault(_react);
+
+var _reactRedux = require("devtools/client/shared/vendor/react-redux");
+
+var _source = require("../../utils/source");
+
+var _selectors = require("../../selectors/index");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/* 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/>. */
+class SourceIcon extends _react.PureComponent {
+  render() {
+    const {
+      shouldHide,
+      source,
+      sourceMetaData
+    } = this.props;
+    const iconClass = (0, _source.getSourceClassnames)(source, sourceMetaData);
+
+    if (shouldHide && shouldHide(iconClass)) {
+      return null;
+    }
+
+    return _react2.default.createElement("img", {
+      className: `source-icon ${iconClass}`
+    });
+  }
+
+}
+
+exports.default = (0, _reactRedux.connect)((state, props) => {
+  return {
+    sourceMetaData: (0, _selectors.getSourceMetaData)(state, props.source.id)
+  };
+})(SourceIcon);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/shared/moz.build
+++ b/devtools/client/debugger/new/src/components/shared/moz.build
@@ -13,10 +13,11 @@ DevToolsModules(
     'BracketArrow.js',
     'Dropdown.js',
     'ManagedTree.js',
     'Modal.js',
     'Popover.js',
     'PreviewFunction.js',
     'ResultList.js',
     'SearchInput.js',
+    'SourceIcon.js',
     'Svg.js',
 )
--- a/devtools/client/debugger/new/src/utils/source.js
+++ b/devtools/client/debugger/new/src/utils/source.js
@@ -427,15 +427,30 @@ function getTextAtPosition(source, locat
 
   if (!lineText) {
     return "";
   }
 
   return lineText.slice(column, column + 100).trim();
 }
 
-function getSourceClassnames(source) {
-  if (source && source.isBlackBoxed) {
+function getSourceClassnames(source, sourceMetaData) {
+  // Conditionals should be ordered by priority of icon!
+  const defaultClassName = "file";
+
+  if (!source || !source.url) {
+    return defaultClassName;
+  }
+
+  if (sourceMetaData && sourceMetaData.framework) {
+    return sourceMetaData.framework.toLowerCase();
+  }
+
+  if (isPretty(source)) {
+    return "prettyPrint";
+  }
+
+  if (source.isBlackBoxed) {
     return "blackBox";
   }
 
-  return sourceTypes[(0, _sourcesTree.getExtension)(source)] || "file";
+  return sourceTypes[(0, _sourcesTree.getExtension)(source)] || defaultClassName;
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/utils/tabs.js
+++ b/devtools/client/debugger/new/src/utils/tabs.js
@@ -1,25 +1,16 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getHiddenTabs = getHiddenTabs;
-exports.getSourceAnnotation = getSourceAnnotation;
 exports.getTabMenuItems = getTabMenuItems;
 
-var _react = require("devtools/client/shared/vendor/react");
-
-var _react2 = _interopRequireDefault(_react);
-
-var _source = require("./source");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
 /* 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/>. */
 
 /*
  * Finds the hidden tabs by comparing the tabs' top offset.
  * hidden tabs will have a great top offset.
  *
@@ -44,38 +35,16 @@ function getHiddenTabs(sourceTabs, sourc
   }
 
   return sourceTabs.filter((tab, index) => {
     const element = sourceTabEls[index];
     return element && hasTopOffset(element);
   });
 }
 
-function getSourceAnnotation(source, sourceMetaData) {
-  const framework = sourceMetaData && sourceMetaData.framework ? sourceMetaData.framework : false;
-
-  if (framework) {
-    return _react2.default.createElement("img", {
-      className: framework.toLowerCase()
-    });
-  }
-
-  if ((0, _source.isPretty)(source)) {
-    return _react2.default.createElement("img", {
-      className: "prettyPrint"
-    });
-  }
-
-  if (source.isBlackBoxed) {
-    return _react2.default.createElement("img", {
-      className: "blackBox"
-    });
-  }
-}
-
 function getTabMenuItems() {
   return {
     closeTab: {
       id: "node-menu-close-tab",
       label: L10N.getStr("sourceTabs.closeTab"),
       accesskey: L10N.getStr("sourceTabs.closeTab.accesskey"),
       disabled: false
     },
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking-from-console.js
@@ -18,16 +18,19 @@ add_task(async function() {
   jsterm.execute("debugger");
 
   // Wait for the debugger to be selected and make sure it's paused
   await waitOnToolbox(toolbox, "jsdebugger-selected");
   is(toolbox.threadClient.state, "paused");
 
   // Create a dbg context
   const dbg = createDebuggerContext(toolbox);
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   // Make sure the thread is paused in the right source and location
   await waitForPaused(dbg);
   is(getCM(dbg).getValue(), "debugger");
   const source = getSelectedSource(getState()).toJS();
   assertPausedLocation(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking.js
@@ -1,16 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests the breakpoints are hit in various situations.
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   // Make sure we can set a top-level breakpoint and it will be hit on
   // reload.
   await addBreakpoint(dbg, "scripts.html", 18);
   reload(dbg);
 
   await waitForDispatch(dbg, "NAVIGATE");
   await waitForSelectedSource(dbg, "doc-scripts.html");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-cond.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-cond.js
@@ -1,13 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function findBreakpoint(dbg, url, line) {
-  const { selectors: { getBreakpoint }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint },
+    getState
+  } = dbg;
   const source = findSource(dbg, url);
   return getBreakpoint(getState(), { sourceId: source.id, line });
 }
 
 function getLineEl(dbg, line) {
   const lines = dbg.win.document.querySelectorAll(".CodeMirror-code > div");
   return lines[line - 1];
 }
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-reloading.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-reloading.js
@@ -21,17 +21,20 @@ function addBreakpoint(dbg, line) {
 
 function assertEditorBreakpoint(dbg, line) {
   const exists = !!getLineEl(dbg, line).querySelector(".new-breakpoint");
   ok(exists, `Breakpoint exists on line ${line}`);
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
-  const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg;
+  const {
+    selectors: { getBreakpoints, getBreakpoint },
+    getState
+  } = dbg;
   const source = findSource(dbg, "simple1.js");
 
   await selectSource(dbg, source.url);
   await addBreakpoint(dbg, 5);
   await addBreakpoint(dbg, 4);
 
   const syncedBps = waitForDispatch(dbg, "SYNC_BREAKPOINT", 2);
   await reload(dbg, "simple1");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints.js
@@ -31,23 +31,29 @@ function disableBreakpoints(dbg, count) 
 
 function enableBreakpoints(dbg, count) {
   const enabled = waitForDispatch(dbg, "ENABLE_BREAKPOINT", count);
   toggleBreakpoints(dbg);
   return enabled;
 }
 
 function findBreakpoint(dbg, url, line) {
-  const { selectors: { getBreakpoint }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint },
+    getState
+  } = dbg;
   const source = findSource(dbg, url);
   return getBreakpoint(getState(), { sourceId: source.id, line });
 }
 
 function findBreakpoints(dbg) {
-  const { selectors: { getBreakpoints }, getState } = dbg;
+  const {
+    selectors: { getBreakpoints },
+    getState
+  } = dbg;
   return getBreakpoints(getState());
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
 
   // Create two breakpoints
   await selectSource(dbg, "simple2");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-browser-content-toolbox.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-browser-content-toolbox.js
@@ -27,17 +27,20 @@ async function disableBreakpoint(dbg, in
 
 async function enableBreakpoint(dbg, index) {
   const enabled = waitForDispatch(dbg, "ENABLE_BREAKPOINT");
   toggleBreakpoint(dbg, index);
   await enabled;
 }
 
 function findBreakpoint(dbg, url, line) {
-  const { selectors: { getBreakpoint }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint },
+    getState
+  } = dbg;
   const source = findSource(dbg, url);
   return getBreakpoint(getState(), { sourceId: source.id, line });
 }
 
 add_task(async function() {
   clearDebuggerPreferences();
 
   info("Open a tab pointing to doc-scripts.html");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-chrome-create.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-chrome-create.js
@@ -4,17 +4,19 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that a chrome debugger can be created in a new process.
  */
 
 // There are shutdown issues for which multiple rejections are left uncaught.
 // See bug 1018184 for resolving these issues.
-const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
+const { PromiseTestUtils } = scopedCuImport(
+  "resource://testing-common/PromiseTestUtils.jsm"
+);
 PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
 PromiseTestUtils.whitelistRejectionsGlobally(/NS_ERROR_FAILURE/);
 
 requestLongerTimeout(5);
 
 const { BrowserToolboxProcess } = ChromeUtils.import(
   "resource://devtools/client/framework/ToolboxProcess.jsm",
   {}
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-gutter.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-gutter.js
@@ -22,17 +22,20 @@ function assertEditorBreakpoint(dbg, lin
       (shouldExist ? "exists" : "does not exist") +
       " on line " +
       line
   );
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
-  const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg;
+  const {
+    selectors: { getBreakpoints, getBreakpoint },
+    getState
+  } = dbg;
   const source = findSource(dbg, "simple1.js");
 
   await selectSource(dbg, source.url);
 
   // Make sure that clicking the gutter creates a breakpoint icon.
   clickGutter(dbg, 4);
   await waitForDispatch(dbg, "ADD_BREAKPOINT");
   is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-highlight.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-highlight.js
@@ -2,24 +2,27 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the editor will always highight the right line, no
 // matter if the source text doesn't exist yet or even if the source
 // doesn't exist.
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
-  const { selectors: { getSource }, getState } = dbg;
+  const {
+    selectors: { getSource },
+    getState
+  } = dbg;
   const sourceUrl = EXAMPLE_URL + "long.js";
 
   // The source itself doesn't even exist yet, and using
   // `selectSourceURL` will set a pending request to load this source
   // and highlight a specific line.
 
-  await selectSource(dbg, sourceUrl, 66)
+  await selectSource(dbg, sourceUrl, 66);
 
   // TODO: revisit highlighting lines when the debugger opens
   // assertHighlightLocation(dbg, "long.js", 66);
 
   log(`Select line 16 and make sure the editor scrolled.`);
   await selectSource(dbg, "long.js", 16);
   await waitForElementWithSelector(dbg, ".CodeMirror-code > .highlight-line");
   assertHighlightLocation(dbg, "long.js", 16);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-select.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-select.js
@@ -5,17 +5,20 @@
 // debugger pauses
 requestLongerTimeout(2);
 
 add_task(async function() {
   // This test runs too slowly on linux debug. I'd like to figure out
   // which is the slowest part of this and make it run faster, but to
   // fix a frequent failure allow a longer timeout.
   const dbg = await initDebugger("doc-scripts.html");
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
   const simple1 = findSource(dbg, "simple1.js");
   const simple2 = findSource(dbg, "simple2.js");
 
   // Set the initial breakpoint.
   await addBreakpoint(dbg, simple1, 4);
   ok(!getSelectedSource(getState()), "No selected source");
 
   // Call the function that we set a breakpoint in.
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-ember-quickstart.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-ember-quickstart.js
@@ -1,15 +1,20 @@
-
 add_task(async function() {
   await pushPref("devtools.debugger.features.map-scopes", true);
 
   const dbg = await initDebugger("ember/quickstart/dist/");
 
-  await invokeWithBreakpoint(dbg, "mapTestFunction", "quickstart/router.js", { line: 13, column: 2 }, async () => {
-    await assertScopes(dbg, [
-      "Module",
-      ["config", "{\u2026}"],
-      "EmberRouter:Class()",
-      "Router:Class()",
-    ]);
-  });
+  await invokeWithBreakpoint(
+    dbg,
+    "mapTestFunction",
+    "quickstart/router.js",
+    { line: 13, column: 2 },
+    async () => {
+      await assertScopes(dbg, [
+        "Module",
+        ["config", "{\u2026}"],
+        "EmberRouter:Class()",
+        "Router:Class()"
+      ]);
+    }
+  );
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions-error.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions-error.js
@@ -19,17 +19,17 @@ function getLabel(dbg, index) {
 }
 
 function getValue(dbg, index) {
   return findElement(dbg, "expressionValue", index).innerText;
 }
 
 async function addExpression(dbg, input) {
   const plusIcon = findElementWithSelector(dbg, expressionSelectors.plusIcon);
-  if(plusIcon) {
+  if (plusIcon) {
     plusIcon.click();
   }
 
   const evaluation = waitForDispatch(dbg, "EVALUATE_EXPRESSION");
   findElementWithSelector(dbg, expressionSelectors.input).focus();
   type(dbg, input);
   pressKey(dbg, "Enter");
   await evaluation;
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
@@ -31,17 +31,17 @@ function assertEmptyValue(dbg, index) {
 
   is(value, null);
 }
 
 async function addExpression(dbg, input) {
   info("Adding an expression");
 
   const plusIcon = findElementWithSelector(dbg, expressionSelectors.plusIcon);
-  if(plusIcon) {
+  if (plusIcon) {
     plusIcon.click();
   }
   findElementWithSelector(dbg, expressionSelectors.input).focus();
   type(dbg, input);
   pressKey(dbg, "Enter");
 
   await waitForDispatch(dbg, "EVALUATE_EXPRESSION");
 }
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-inline-cache.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-inline-cache.js
@@ -24,109 +24,121 @@ server.registerPathHandler("/inline-cach
     <script>
       let x = ${docValue};
     </script>
     </head>
     </html>
   `);
 });
 
-const SOURCE_URL = `http://localhost:${server.identity.primaryPort}/inline-cache.html`;
+const SOURCE_URL = `http://localhost:${
+  server.identity.primaryPort
+}/inline-cache.html`;
 
 /**
  * This is meant to simulate the developer editing the inline source and saving.
  * Effectively, we change the source during the test at specific controlled points.
  */
 function makeChanges() {
   docValue++;
 }
 
 function getPageValue(tab) {
-  return ContentTask.spawn(tab.linkedBrowser, {}, function () {
+  return ContentTask.spawn(tab.linkedBrowser, {}, function() {
     return content.document.querySelector("script").textContent.trim();
   });
 }
 
 async function reloadTabAndDebugger(tab, dbg) {
   let navigated = waitForDispatch(dbg, "NAVIGATE");
   let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   await reload(dbg, "inline-cache.html");
-  return Promise.all([ navigated, loaded ]);
+  return Promise.all([navigated, loaded]);
 }
 
-add_task(async function () {
+add_task(async function() {
   info("Load document with inline script");
   const tab = await addTab(SOURCE_URL);
   info("Open debugger");
   clearDebuggerPreferences();
   const toolbox = await openToolboxForTab(tab, "jsdebugger");
   const dbg = createDebuggerContext(toolbox);
   info("Reload tab to ensure debugger finds script");
   await reloadTabAndDebugger(tab, dbg);
   let pageValue = await getPageValue(tab);
   is(pageValue, "let x = 1;", "Content loads from network, has doc value 1");
   await waitForSource(dbg, "inline-cache.html");
   await selectSource(dbg, "inline-cache.html");
   await waitForLoadedSource(dbg, "inline-cache.html");
   let dbgValue = await findSource(dbg, "inline-cache.html");
   info(`Debugger text: ${dbgValue.text}`);
-  ok(dbgValue.text.includes(pageValue),
-     "Debugger loads from cache, gets value 1 like page");
+  ok(
+    dbgValue.text.includes(pageValue),
+    "Debugger loads from cache, gets value 1 like page"
+  );
 
   info("Disable HTTP cache for page");
   await toolbox.target.activeTab.reconfigure({ cacheDisabled: true });
   makeChanges();
 
   info("Reload inside debugger with toolbox caching disabled (attempt 1)");
   await reloadTabAndDebugger(tab, dbg);
   pageValue = await getPageValue(tab);
   is(pageValue, "let x = 2;", "Content loads from network, has doc value 2");
   await waitForLoadedSource(dbg, "inline-cache.html");
   dbgValue = await findSource(dbg, "inline-cache.html");
   info(`Debugger text: ${dbgValue.text}`);
-  ok(dbgValue.text.includes(pageValue),
-     "Debugger loads from network, gets value 2 like page");
+  ok(
+    dbgValue.text.includes(pageValue),
+    "Debugger loads from network, gets value 2 like page"
+  );
 
   makeChanges();
 
   info("Reload inside debugger with toolbox caching disabled (attempt 2)");
   await reloadTabAndDebugger(tab, dbg);
   pageValue = await getPageValue(tab);
   is(pageValue, "let x = 3;", "Content loads from network, has doc value 3");
   await waitForLoadedSource(dbg, "inline-cache.html");
   dbgValue = await findSource(dbg, "inline-cache.html");
   info(`Debugger text: ${dbgValue.text}`);
-  ok(dbgValue.text.includes(pageValue),
-     "Debugger loads from network, gets value 3 like page");
+  ok(
+    dbgValue.text.includes(pageValue),
+    "Debugger loads from network, gets value 3 like page"
+  );
 
   info("Enable HTTP cache for page");
   await toolbox.target.activeTab.reconfigure({ cacheDisabled: false });
   makeChanges();
 
   // Even though the HTTP cache is now enabled, Gecko sets the VALIDATE_ALWAYS flag when
   // reloading the page.  So, it will always make a request to the server for the main
   // document contents.
 
   info("Reload inside debugger with toolbox caching enabled (attempt 1)");
   await reloadTabAndDebugger(tab, dbg);
   pageValue = await getPageValue(tab);
   is(pageValue, "let x = 4;", "Content loads from network, has doc value 4");
   await waitForLoadedSource(dbg, "inline-cache.html");
   dbgValue = await findSource(dbg, "inline-cache.html");
   info(`Debugger text: ${dbgValue.text}`);
-  ok(dbgValue.text.includes(pageValue),
-     "Debugger loads from cache, gets value 4 like page");
+  ok(
+    dbgValue.text.includes(pageValue),
+    "Debugger loads from cache, gets value 4 like page"
+  );
 
   makeChanges();
 
   info("Reload inside debugger with toolbox caching enabled (attempt 2)");
   await reloadTabAndDebugger(tab, dbg);
   pageValue = await getPageValue(tab);
   is(pageValue, "let x = 5;", "Content loads from network, has doc value 5");
   await waitForLoadedSource(dbg, "inline-cache.html");
   dbgValue = await findSource(dbg, "inline-cache.html");
   info(`Debugger text: ${dbgValue.text}`);
-  ok(dbgValue.text.includes(pageValue),
-     "Debugger loads from cache, gets value 5 like page");
+  ok(
+    dbgValue.text.includes(pageValue),
+    "Debugger loads from cache, gets value 5 like page"
+  );
 
   await toolbox.destroy();
   await removeTab(tab);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-navigation.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-navigation.js
@@ -15,17 +15,20 @@ const sources = [
 ];
 
 /**
  * Test navigating
  * navigating while paused will reset the pause state and sources
  */
 add_task(async function() {
   const dbg = await initDebugger("doc-script-switching.html");
-  const { selectors: { getSelectedSource, isPaused }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource, isPaused },
+    getState
+  } = dbg;
 
   invokeInTab("firstCall");
   await waitForPaused(dbg);
 
   await navigate(dbg, "doc-scripts.html", "simple1.js");
   await addBreakpoint(dbg, "simple1.js", 4);
   invokeInTab("main");
   await waitForPaused(dbg);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-outline.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-outline.js
@@ -9,32 +9,53 @@ function getItems(dbg) {
 }
 
 function getNthItem(dbg, index) {
   return findElement(dbg, "outlineItem", index);
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   await selectSource(dbg, "simple1", 1);
 
   findElementWithSelector(dbg, ".outline-tab").click();
   is(getItems(dbg).length, 5, "5 items in the list");
 
   // click on an element
   const item = getNthItem(dbg, 3);
   is(item.innerText, "evaledFunc()", "got evaled func");
   item.click();
   assertHighlightLocation(dbg, "simple1", 15);
 
   // Ensure "main()" is the first function listed
-  const firstFunction = findElementWithSelector(dbg, '.outline-list__element .function-signature');
-  is(firstFunction.innerText, "main()", "Natural first function is first listed");
+  const firstFunction = findElementWithSelector(
+    dbg,
+    ".outline-list__element .function-signature"
+  );
+  is(
+    firstFunction.innerText,
+    "main()",
+    "Natural first function is first listed"
+  );
   // Sort the list
   findElementWithSelector(dbg, ".outline-footer button").click();
   // Button becomes active to show alphabetization
-  is(findElementWithSelector(dbg, ".outline-footer button").className, "active", "Alphabetize button is highlighted when active");
+  is(
+    findElementWithSelector(dbg, ".outline-footer button").className,
+    "active",
+    "Alphabetize button is highlighted when active"
+  );
   // Ensure "doEval()" is the first function listed after alphabetization
-  const firstAlphaFunction = findElementWithSelector(dbg, '.outline-list__element .function-signature');
-  is(firstAlphaFunction.innerText.replace("λ", ""), "doEval()", "Alphabetized first function is correct");
+  const firstAlphaFunction = findElementWithSelector(
+    dbg,
+    ".outline-list__element .function-signature"
+  );
+  is(
+    firstAlphaFunction.innerText.replace("λ", ""),
+    "doEval()",
+    "Alphabetized first function is correct"
+  );
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-exceptions.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-exceptions.js
@@ -26,32 +26,28 @@ add_task(async function() {
   log("2. Test pausing on an uncaught exception");
   await togglePauseOnExceptions(dbg, true, true);
   uncaughtException();
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
   await resume(dbg);
   await waitForActive(dbg);
 
-
   log("3. Test pausing on a caught Error");
   caughtException();
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
 
-
   log("3.b Test pausing in the catch statement");
   await resume(dbg);
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
   await resume(dbg);
 
-
   log("4. Test skipping a caught error");
   await togglePauseOnExceptions(dbg, true, false);
   caughtException();
 
-
   log("4.b Test pausing in the catch statement");
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
   await resume(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-on-next.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-on-next.js
@@ -2,14 +2,14 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that when  pause on next is selected, we  pause on the next execution
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
 
   clickElement(dbg, "pause");
-  await waitForState(dbg, state => dbg.selectors.getIsWaitingOnBreak(state))
+  await waitForState(dbg, state => dbg.selectors.getIsWaitingOnBreak(state));
   invokeInTab("simple");
 
   await waitForPaused(dbg, "simple3");
   assertPaused(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
@@ -1,36 +1,35 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
- requestLongerTimeout(2);
+requestLongerTimeout(2);
 
- async function stepOvers(dbg, count, onStep = () => {}) {
-   let i = 0;
-   while (i++ <= count) {
-     await dbg.actions.stepOver();
-     await waitForPaused(dbg);
-     onStep(dbg.getState());
-   }
- }
-
+async function stepOvers(dbg, count, onStep = () => {}) {
+  let i = 0;
+  while (i++ <= count) {
+    await dbg.actions.stepOver();
+    await waitForPaused(dbg);
+    onStep(dbg.getState());
+  }
+}
 
 async function testCase(dbg, { name, count, steps }) {
   invokeInTab(name);
-  let locations = []
+  let locations = [];
 
   await stepOvers(dbg, count, state => {
-    locations.push(dbg.selectors.getTopFrame(state).location)
+    locations.push(dbg.selectors.getTopFrame(state).location);
   });
 
-  const formattedSteps = locations.map(
-    ({line, column}) => `(${line},${column})`
-  ).join(", ")
+  const formattedSteps = locations
+    .map(({ line, column }) => `(${line},${column})`)
+    .join(", ");
 
-  is(formattedSteps, steps, name)
+  is(formattedSteps, steps, name);
 
   await resume(dbg);
 }
 
 add_task(async function test() {
   const dbg = await initDebugger("doc-pause-points.html");
 
   await testCase(dbg, {
@@ -49,11 +48,12 @@ add_task(async function test() {
     name: "sequences",
     count: 4,
     steps: "(23,2), (25,8), (29,8), (34,2), (37,0)"
   });
 
   await testCase(dbg, {
     name: "flow",
     count: 8,
-    steps: "(16,2), (17,12), (18,6), (19,8), (19,17), (19,8), (19,17), (19,8), (20,0)"
+    steps:
+      "(16,2), (17,12), (18,6), (19,8), (19,17), (19,8), (19,17), (19,8), (20,0)"
   });
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js
@@ -25,17 +25,17 @@ async function waitForConsoleLink(dbg, t
 }
 
 // Tests that pretty-printing updates console messages.
 add_task(async function() {
   const dbg = await initDebugger("doc-minified.html");
   invokeInTab("arithmetic");
 
   info("Switch to console and check message");
-  await waitForConsoleLink(dbg,  "math.min.js:3:65");
+  await waitForConsoleLink(dbg, "math.min.js:3:65");
 
   info("Switch back to debugger and pretty-print");
   await dbg.toolbox.selectTool("jsdebugger");
   await selectSource(dbg, "math.min.js", 2);
 
   clickElement(dbg, "prettyPrintButton");
   await waitForSelectedSource(dbg, "math.min.js:formatted");
 
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js
@@ -1,16 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test hovering in a script that is paused on load
 // and doesn't have functions.
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   navigate(dbg, "doc-on-load.html");
 
   // wait for `top-level.js` to load and to pause at a debugger statement
   await waitForSelectedSource(dbg, "top-level.js");
   await waitForPaused(dbg);
 
   await assertPreviews(dbg, [
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-source-maps.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-source-maps.js
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-
 async function assertNoTooltip(dbg) {
   await waitForTime(200);
   const el = findElement(dbg, "tooltip");
-  is(el, null, "Tooltip should not exist")
+  is(el, null, "Tooltip should not exist");
 }
 
 function assertPreviewTooltip(dbg, { result, expression }) {
   const previewEl = findElement(dbg, "tooltip");
   is(previewEl.innerText, result, "Preview text shown to user");
 
   const preview = dbg.selectors.getPreview(dbg.getState());
   is(`${preview.result}`, result, "Preview.result");
@@ -30,36 +29,38 @@ function assertPreviewPopup(dbg, { field
     "Preview.result"
   );
   is(preview.updating, false, "Preview.updating");
   is(preview.expression, expression, "Preview.expression");
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-sourcemaps.html");
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
   await selectSource(dbg, "times2");
   await addBreakpoint(dbg, "times2", 2);
 
   invokeInTab("keepMeAlive");
   await waitForPaused(dbg);
   await waitForSelectedSource(dbg, "times2");
 
-  info(`Test previewing in the original location`)
+  info(`Test previewing in the original location`);
   await assertPreviews(dbg, [
     { line: 2, column: 10, result: 4, expression: "x" }
   ]);
 
-  info(`Test previewing in the generated location`)
+  info(`Test previewing in the generated location`);
   await dbg.actions.jumpToMappedSelectedLocation();
   await waitForSelectedSource(dbg, "bundle.js");
   await assertPreviews(dbg, [
     { line: 70, column: 11, result: 4, expression: "x" }
   ]);
 
-
   info(`Test that you can not preview in another original file`);
   await selectSource(dbg, "output");
   await hoverAtPos(dbg, { line: 2, ch: 16 });
-  await assertNoTooltip(dbg)
+  await assertNoTooltip(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js
@@ -20,17 +20,17 @@ async function waitForBreakpoint(dbg, lo
 add_task(async function() {
   const dbg = await initDebugger("reload/doc-reload.html");
 
   await waitForSource(dbg, "sjs_code_reload");
   await selectSource(dbg, "sjs_code_reload");
   await addBreakpoint(dbg, "sjs_code_reload", 2);
 
   await reload(dbg, "sjs_code_reload.sjs");
-  await waitForSelectedSource(dbg, "sjs_code_reload.sjs")
+  await waitForSelectedSource(dbg, "sjs_code_reload.sjs");
 
   const source = findSource(dbg, "sjs_code_reload");
   const location = { sourceId: source.id, line: 6 };
 
   await waitForBreakpoint(dbg, location);
 
   const breakpoints = dbg.selectors.getBreakpoints(dbg.getState());
   const breakpointList = breakpoints.valueSeq().toJS();
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-replay.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-replay.js
@@ -38,17 +38,20 @@ async function clickStepOut(dbg) {
   return waitForPaused(dbg);
 }
 
 async function clickResume(dbg) {
   return clickButton(dbg, "resume");
 }
 
 function assertHistoryPosition(dbg, position) {
-  const { selectors: { getHistoryPosition, getHistoryFrame }, getState } = dbg;
+  const {
+    selectors: { getHistoryPosition, getHistoryFrame },
+    getState
+  } = dbg;
 
   ok(
     getHistoryPosition(getState()) === position - 1,
     "has correct position in history"
   );
 }
 
 /**
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
@@ -1,16 +1,26 @@
-
-async function evalInConsoleAtPoint(dbg, fixture, { line, column }, statements) {
+async function evalInConsoleAtPoint(
+  dbg,
+  fixture,
+  { line, column },
+  statements
+) {
   const filename = `fixtures/${fixture}/input.js`;
   const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
 
-  await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async () => {
-    await assertConsoleEval(dbg, statements);
-  });
+  await invokeWithBreakpoint(
+    dbg,
+    fnName,
+    filename,
+    { line, column },
+    async () => {
+      await assertConsoleEval(dbg, statements);
+    }
+  );
 
   ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
 }
 
 async function assertConsoleEval(dbg, statements) {
   const jsterm = (await dbg.toolbox.selectTool("webconsole")).hud.jsterm;
 
   for (const [index, statement] of statements.entries()) {
@@ -29,29 +39,35 @@ async function assertConsoleEval(dbg, st
 add_task(async function() {
   await pushPref("devtools.debugger.features.map-scopes", true);
 
   const dbg = await initDebugger("doc-sourcemapped.html");
 
   await evalInConsoleAtPoint(dbg, "babel-eval-maps", { line: 14, column: 4 }, [
     "one === 1",
     "two === 4",
-    "three === 5",
+    "three === 5"
   ]);
 
-  await evalInConsoleAtPoint(dbg, "babel-modules-cjs", { line: 20, column: 2 }, [
-    `aDefault === "a-default"`,
-    `anAliased === "an-original"`,
-    `aNamed === "a-named"`,
-    `aDefault2 === "a-default2"`,
-    `anAliased2 === "an-original2"`,
-    `aNamed2 === "a-named2"`,
-    `aDefault3 === "a-default3"`,
-    `anAliased3 === "an-original3"`,
-    `aNamed3 === "a-named3"`,
-  ]);
+  await evalInConsoleAtPoint(
+    dbg,
+    "babel-modules-cjs",
+    { line: 20, column: 2 },
+    [
+      `aDefault === "a-default"`,
+      `anAliased === "an-original"`,
+      `aNamed === "a-named"`,
+      `aDefault2 === "a-default2"`,
+      `anAliased2 === "an-original2"`,
+      `aNamed2 === "a-named2"`,
+      `aDefault3 === "a-default3"`,
+      `anAliased3 === "an-original3"`,
+      `aNamed3 === "a-named3"`
+    ]
+  );
 
-  await evalInConsoleAtPoint(dbg, "babel-shadowed-vars", { line: 18, column: 6 }, [
-    `aVar === "var3"`,
-    `aLet === "let3"`,
-    `aConst === "const3"`,
-  ]);
+  await evalInConsoleAtPoint(
+    dbg,
+    "babel-shadowed-vars",
+    { line: 18, column: 6 },
+    [`aVar === "var3"`, `aLet === "let3"`, `aConst === "const3"`]
+  );
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-preview.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-preview.js
@@ -5,183 +5,187 @@
 requestLongerTimeout(3);
 
 async function breakpointPreviews(dbg, fixture, { line, column }, previews) {
   const filename = `fixtures/${fixture}/input.js`;
   const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
 
   log(`Starting ${fixture} tests`);
 
-  await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async () => {
-    await assertPreviews(dbg, previews);
-  });
+  await invokeWithBreakpoint(
+    dbg,
+    fnName,
+    filename,
+    { line, column },
+    async () => {
+      await assertPreviews(dbg, previews);
+    }
+  );
 
   ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
 }
 
 function testForOf(dbg) {
   return breakpointPreviews(dbg, "babel-for-of", { line: 5, column: 4 }, [
     {
       line: 5,
       column: 7,
       expression: "doThing",
-      result: "doThing(arg)",
+      result: "doThing(arg)"
     },
     {
       line: 5,
       column: 13,
       expression: "x",
-      result: "1",
+      result: "1"
     },
     {
       line: 8,
       column: 16,
       expression: "doThing",
-      result: "doThing(arg)",
-    },
+      result: "doThing(arg)"
+    }
   ]);
 }
 
 function testShadowing(dbg) {
-  return breakpointPreviews(dbg, "babel-shadowed-vars", { line: 18, column: 6 }, [
+  return breakpointPreviews(
+    dbg,
+    "babel-shadowed-vars",
+    { line: 18, column: 6 },
+    [
       // These aren't what the user would expect, but we test them anyway since
       // they reflect what this actually returns. These shadowed bindings read
       // the binding closest to the current frame's scope even though their
       // actual value is different.
       {
         line: 2,
         column: 9,
         expression: "aVar",
-        result: '"var3"',
+        result: '"var3"'
       },
       {
         line: 3,
         column: 9,
         expression: "_aLet2;",
-        result: '"let3"',
+        result: '"let3"'
       },
       {
         line: 4,
         column: 11,
         expression: "_aConst2;",
-        result: '"const3"',
+        result: '"const3"'
       },
       {
         line: 10,
         column: 11,
         expression: "aVar",
-        result: '"var3"',
+        result: '"var3"'
       },
       {
         line: 11,
         column: 11,
         expression: "_aLet2;",
-        result: '"let3"',
+        result: '"let3"'
       },
       {
         line: 12,
         column: 13,
         expression: "_aConst2;",
-        result: '"const3"',
+        result: '"const3"'
       },
 
       // These actually result in the values the user would expect.
       {
         line: 14,
         column: 13,
         expression: "aVar",
-        result: '"var3"',
+        result: '"var3"'
       },
       {
         line: 15,
         column: 13,
         expression: "_aLet2;",
-        result: '"let3"',
+        result: '"let3"'
       },
       {
         line: 16,
         column: 13,
         expression: "_aConst2;",
-        result: '"const3"',
-      },
-    ]);
+        result: '"const3"'
+      }
+    ]
+  );
 }
 
 function testImportedBindings(dbg) {
   return breakpointPreviews(dbg, "babel-modules-cjs", { line: 20, column: 2 }, [
-   {
-     line: 22,
-     column: 16,
-     expression: "_mod2.default;",
-     result: '"a-default"',
-   },
-   {
-     line: 23,
-     column: 16,
-     expression: "_mod4.original;",
-     result: '"an-original"',
-   },
-   {
-     line: 24,
-     column: 16,
-     expression: "_mod3.aNamed;",
-     result: '"a-named"',
-   },
-   {
-     line: 25,
-     column: 16,
-     expression: "_mod3.aNamed;",
-     result: '"a-named"',
-   },
-   {
-     line: 26,
-     column: 16,
-     expression: "aNamespace",
-     fields: [
-       ['aNamed', 'a-named'],
-       ['default', 'a-default'],
-     ],
-   },
-   {
-     line: 31,
-     column: 20,
-     expression: "_mod7.default;",
-     result: '"a-default2"',
-   },
-   {
-     line: 32,
-     column: 20,
-     expression: "_mod9.original;",
-     result: '"an-original2"',
-   },
-   {
-     line: 33,
-     column: 20,
-     expression: "_mod8.aNamed2;",
-     result: '"a-named2"',
-   },
-   {
-     line: 34,
-     column: 20,
-     expression: "_mod8.aNamed2;",
-     result: '"a-named2"',
-   },
-   {
-     line: 35,
-     column: 20,
-     expression: "aNamespace2",
-     fields: [
-       ['aNamed', 'a-named2'],
-       ['default', 'a-default2'],
-     ],
-   },
- ]);
+    {
+      line: 22,
+      column: 16,
+      expression: "_mod2.default;",
+      result: '"a-default"'
+    },
+    {
+      line: 23,
+      column: 16,
+      expression: "_mod4.original;",
+      result: '"an-original"'
+    },
+    {
+      line: 24,
+      column: 16,
+      expression: "_mod3.aNamed;",
+      result: '"a-named"'
+    },
+    {
+      line: 25,
+      column: 16,
+      expression: "_mod3.aNamed;",
+      result: '"a-named"'
+    },
+    {
+      line: 26,
+      column: 16,
+      expression: "aNamespace",
+      fields: [["aNamed", "a-named"], ["default", "a-default"]]
+    },
+    {
+      line: 31,
+      column: 20,
+      expression: "_mod7.default;",
+      result: '"a-default2"'
+    },
+    {
+      line: 32,
+      column: 20,
+      expression: "_mod9.original;",
+      result: '"an-original2"'
+    },
+    {
+      line: 33,
+      column: 20,
+      expression: "_mod8.aNamed2;",
+      result: '"a-named2"'
+    },
+    {
+      line: 34,
+      column: 20,
+      expression: "_mod8.aNamed2;",
+      result: '"a-named2"'
+    },
+    {
+      line: 35,
+      column: 20,
+      expression: "aNamespace2",
+      fields: [["aNamed", "a-named2"], ["default", "a-default2"]]
+    }
+  ]);
 }
 
-
 add_task(async function() {
   await pushPref("devtools.debugger.features.map-scopes", true);
   const dbg = await initDebugger("doc-sourcemapped.html");
 
-  await testForOf(dbg)
-  await testShadowing(dbg)
-  await testImportedBindings(dbg)
+  await testForOf(dbg);
+  await testShadowing(dbg);
+  await testImportedBindings(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
@@ -5,19 +5,25 @@
 requestLongerTimeout(6);
 
 // Tests loading sourcemapped sources for Babel's compile output.
 
 async function breakpointScopes(dbg, fixture, { line, column }, scopes) {
   const filename = `fixtures/${fixture}/input.`;
   const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
 
-  await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async () => {
-    await assertScopes(dbg, scopes);
-  });
+  await invokeWithBreakpoint(
+    dbg,
+    fnName,
+    filename,
+    { line, column },
+    async () => {
+      await assertScopes(dbg, scopes);
+    }
+  );
 
   ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
 }
 
 add_task(async function() {
   await pushPref("devtools.debugger.features.map-scopes", true);
 
   const dbg = await initDebugger("doc-sourcemapped.html");
@@ -26,17 +32,17 @@ add_task(async function() {
     "Module",
     "AnotherThing()",
     "AppComponent()",
     "decoratorFactory()",
     "def()",
     "ExportedOther()",
     "ExpressionClass:Foo()",
     "fn()",
-    ["ns", '{\u2026}'],
+    ["ns", "{\u2026}"],
     "SubDecl()",
     "SubVar:SubExpr()"
   ]);
 
   await breakpointScopes(dbg, "babel-eval-maps", { line: 14, column: 4 }, [
     "Block",
     ["three", "5"],
     ["two", "4"],
@@ -76,17 +82,17 @@ add_task(async function() {
   ]);
 
   await breakpointScopes(
     dbg,
     "babel-line-start-bindings-es6",
     { line: 19, column: 4 },
     [
       "Block",
-      ["<this>", '{\u2026}'],
+      ["<this>", "{\u2026}"],
       ["one", "1"],
       ["two", "2"],
       "root",
       ["aFunc", "(optimized away)"],
       "Module",
       "root()"
     ]
   );
@@ -222,41 +228,47 @@ add_task(async function() {
 
   await breakpointScopes(dbg, "babel-commonjs", { line: 7, column: 2 }, [
     "Module",
     ["alsoModuleScoped", "2"],
     ["moduleScoped", "1"],
     "thirdModuleScoped()"
   ]);
 
-  await breakpointScopes(dbg, "babel-out-of-order-declarations-cjs", { line: 8, column: 4 }, [
-    "callback",
-    "fn()",
-    ["val", "undefined"],
-    "root",
-    ["callback", "(optimized away)"],
-    ["fn", "(optimized away)"],
-    ["val", "(optimized away)"],
-    "Module",
+  await breakpointScopes(
+    dbg,
+    "babel-out-of-order-declarations-cjs",
+    { line: 8, column: 4 },
+    [
+      "callback",
+      "fn()",
+      ["val", "undefined"],
+      "root",
+      ["callback", "(optimized away)"],
+      ["fn", "(optimized away)"],
+      ["val", "(optimized away)"],
+      "Module",
 
-    // This value is currently optimized away, which isn't 100% accurate.
-    // Because import declarations is the last thing in the file, our current
-    // logic doesn't cover _both_ 'var' statements that it generates,
-    // making us use the first, optimized-out binding. Given that imports
-    // are almost never the last thing in a file though, this is probably not
-    // a huge deal for now.
-    ["aDefault", "(optimized away)"],
-    ["root", "(optimized away)"],
-    ["val", "(optimized away)"],
-  ]);
-  await breakpointScopes(dbg, "babel-flowtype-bindings", { line: 8, column: 2 }, [
-    "Module",
-    ["aConst", '"a-const"'],
-    "root()"
-  ]);
+      // This value is currently optimized away, which isn't 100% accurate.
+      // Because import declarations is the last thing in the file, our current
+      // logic doesn't cover _both_ 'var' statements that it generates,
+      // making us use the first, optimized-out binding. Given that imports
+      // are almost never the last thing in a file though, this is probably not
+      // a huge deal for now.
+      ["aDefault", "(optimized away)"],
+      ["root", "(optimized away)"],
+      ["val", "(optimized away)"]
+    ]
+  );
+  await breakpointScopes(
+    dbg,
+    "babel-flowtype-bindings",
+    { line: 8, column: 2 },
+    ["Module", ["aConst", '"a-const"'], "root()"]
+  );
 
   await breakpointScopes(dbg, "babel-switches", { line: 7, column: 6 }, [
     "Switch",
     ["val", "2"],
     "Block",
     ["val", "1"],
     "Module",
     "root()"
@@ -279,59 +291,69 @@ add_task(async function() {
     "Catch",
     ["err", '"AnError"'],
     "Block",
     ["one", "1"],
     "Module",
     "root()"
   ]);
 
-  await breakpointScopes(dbg, "babel-modules-webpack", { line: 20, column: 2 }, [
-    "Module",
-    ["aDefault", '"a-default"'],
-    ["aDefault2", '"a-default2"'],
-    ["aDefault3", '"a-default3"'],
-    ["anAliased", "Getter"],
-    ["anAliased2", "Getter"],
-    ["anAliased3", "Getter"],
-    ["aNamed", "Getter"],
-    ["aNamed2", "Getter"],
-    ["aNamed3", "Getter"],
-    ["aNamespace", "{\u2026}"],
-    ["aNamespace2", "{\u2026}"],
-    ["aNamespace3", "{\u2026}"],
-    ["anotherNamed", "Getter"],
-    ["anotherNamed2", "Getter"],
-    ["anotherNamed3", "Getter"],
-    ["example", "(optimized away)"],
-    ["optimizedOut", "(optimized away)"],
-    "root()"
-  ]);
+  await breakpointScopes(
+    dbg,
+    "babel-modules-webpack",
+    { line: 20, column: 2 },
+    [
+      "Module",
+      ["aDefault", '"a-default"'],
+      ["aDefault2", '"a-default2"'],
+      ["aDefault3", '"a-default3"'],
+      ["anAliased", "Getter"],
+      ["anAliased2", "Getter"],
+      ["anAliased3", "Getter"],
+      ["aNamed", "Getter"],
+      ["aNamed2", "Getter"],
+      ["aNamed3", "Getter"],
+      ["aNamespace", "{\u2026}"],
+      ["aNamespace2", "{\u2026}"],
+      ["aNamespace3", "{\u2026}"],
+      ["anotherNamed", "Getter"],
+      ["anotherNamed2", "Getter"],
+      ["anotherNamed3", "Getter"],
+      ["example", "(optimized away)"],
+      ["optimizedOut", "(optimized away)"],
+      "root()"
+    ]
+  );
 
-  await breakpointScopes(dbg, "babel-modules-webpack-es6", { line: 20, column: 2 }, [
-    "Module",
-    ["aDefault", '"a-default"'],
-    ["aDefault2", '"a-default2"'],
-    ["aDefault3", '"a-default3"'],
-    ["anAliased", '"an-original"'],
-    ["anAliased2", '"an-original2"'],
-    ["anAliased3", '"an-original3"'],
-    ["aNamed", '"a-named"'],
-    ["aNamed2", '"a-named2"'],
-    ["aNamed3", '"a-named3"'],
-    ["aNamespace", "{\u2026}"],
-    ["aNamespace2", "{\u2026}"],
-    ["aNamespace3", "{\u2026}"],
-    ["anotherNamed", '"a-named"'],
-    ["anotherNamed2", '"a-named2"'],
-    ["anotherNamed3", '"a-named3"'],
-    ["example", "(optimized away)"],
-    ["optimizedOut", "(optimized away)"],
-    "root()"
-  ]);
+  await breakpointScopes(
+    dbg,
+    "babel-modules-webpack-es6",
+    { line: 20, column: 2 },
+    [
+      "Module",
+      ["aDefault", '"a-default"'],
+      ["aDefault2", '"a-default2"'],
+      ["aDefault3", '"a-default3"'],
+      ["anAliased", '"an-original"'],
+      ["anAliased2", '"an-original2"'],
+      ["anAliased3", '"an-original3"'],
+      ["aNamed", '"a-named"'],
+      ["aNamed2", '"a-named2"'],
+      ["aNamed3", '"a-named3"'],
+      ["aNamespace", "{\u2026}"],
+      ["aNamespace2", "{\u2026}"],
+      ["aNamespace3", "{\u2026}"],
+      ["anotherNamed", '"a-named"'],
+      ["anotherNamed2", '"a-named2"'],
+      ["anotherNamed3", '"a-named3"'],
+      ["example", "(optimized away)"],
+      ["optimizedOut", "(optimized away)"],
+      "root()"
+    ]
+  );
 
   await breakpointScopes(
     dbg,
     "webpack-line-mappings",
     { line: 11, column: 0 },
     [
       "Block",
       ["<this>", '"this-value"'],
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-stepping.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-stepping.js
@@ -3,25 +3,34 @@
 
 // Tests for stepping through Babel's compile output.
 requestLongerTimeout(4);
 
 async function breakpointSteps(dbg, fixture, { line, column }, steps) {
   const filename = `fixtures/${fixture}/input.js`;
   const fnName = fixture.replace(/-([a-z])/g, (s, c) => c.toUpperCase());
 
-  await invokeWithBreakpoint(dbg, fnName, filename, { line, column }, async source => {
-    await runSteps(dbg, source, steps);
-  });
+  await invokeWithBreakpoint(
+    dbg,
+    fnName,
+    filename,
+    { line, column },
+    async source => {
+      await runSteps(dbg, source, steps);
+    }
+  );
 
   ok(true, `Ran tests for ${fixture} at line ${line} column ${column}`);
 }
 
 async function runSteps(dbg, source, steps) {
-  const { selectors: { getVisibleSelectedFrame }, getState } = dbg;
+  const {
+    selectors: { getVisibleSelectedFrame },
+    getState
+  } = dbg;
 
   for (const [i, [type, position]] of steps.entries()) {
     switch (type) {
       case "stepOver":
         await stepOver(dbg);
         break;
       case "stepIn":
         await stepIn(dbg);
@@ -36,39 +45,49 @@ async function runSteps(dbg, source, ste
     is(location.line, position.line, `Step ${i} has correct line`);
     is(location.column, position.column, `Step ${i} has correct column`);
 
     assertPausedLocation(dbg);
   }
 }
 
 function testStepOverForOf(dbg) {
-  return breakpointSteps(dbg, "babel-step-over-for-of", { line: 4, column: 2 }, [
-    ["stepOver", { line: 6, column: 2 }],
-    ["stepOver", { line: 7, column: 4 }],
-    ["stepOver", { line: 6, column: 2 }],
-    ["stepOver", { line: 7, column: 4 }],
-    ["stepOver", { line: 6, column: 2 }],
-    ["stepOver", { line: 10, column: 2 }]
-  ]);
+  return breakpointSteps(
+    dbg,
+    "babel-step-over-for-of",
+    { line: 4, column: 2 },
+    [
+      ["stepOver", { line: 6, column: 2 }],
+      ["stepOver", { line: 7, column: 4 }],
+      ["stepOver", { line: 6, column: 2 }],
+      ["stepOver", { line: 7, column: 4 }],
+      ["stepOver", { line: 6, column: 2 }],
+      ["stepOver", { line: 10, column: 2 }]
+    ]
+  );
 }
 
 // This codifies the current behavior, but stepping twice over the for
 // header isn't ideal.
 function testStepOverForOfArray(dbg) {
-  return breakpointSteps(dbg, "babel-step-over-for-of-array", { line: 3, column: 2 }, [
-    ["stepOver", { line: 5, column: 2 }],
-    ["stepOver", { line: 5, column: 7 }],
-    ["stepOver", { line: 6, column: 4 }],
-    ["stepOver", { line: 5, column: 2 }],
-    ["stepOver", { line: 5, column: 7 }],
-    ["stepOver", { line: 6, column: 4 }],
-    ["stepOver", { line: 5, column: 2 }],
-    ["stepOver", { line: 9, column: 2 }]
-  ]);
+  return breakpointSteps(
+    dbg,
+    "babel-step-over-for-of-array",
+    { line: 3, column: 2 },
+    [
+      ["stepOver", { line: 5, column: 2 }],
+      ["stepOver", { line: 5, column: 7 }],
+      ["stepOver", { line: 6, column: 4 }],
+      ["stepOver", { line: 5, column: 2 }],
+      ["stepOver", { line: 5, column: 7 }],
+      ["stepOver", { line: 6, column: 4 }],
+      ["stepOver", { line: 5, column: 2 }],
+      ["stepOver", { line: 9, column: 2 }]
+    ]
+  );
 }
 
 // The closure means it isn't actually possible to step into the for body,
 // and Babel doesn't map the _loop() call, so we step past it automatically.
 function testStepOveForOfClosure(dbg) {
   return breakpointSteps(
     dbg,
     "babel-step-over-for-of-closure",
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-bogus.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-bogus.js
@@ -3,17 +3,20 @@
 
 // Test that an error while loading a sourcemap does not break
 // debugging.
 requestLongerTimeout(2);
 
 add_task(async function() {
   // NOTE: the CORS call makes the test run times inconsistent
   const dbg = await initDebugger("doc-sourcemap-bogus.html");
-  const { selectors: { getSources }, getState } = dbg;
+  const {
+    selectors: { getSources },
+    getState
+  } = dbg;
 
   await selectSource(dbg, "bogus-map.js");
 
   // We should still be able to set breakpoints and pause in the
   // generated source.
   await addBreakpoint(dbg, "bogus-map.js", 4);
   invokeInTab("runCode");
   await waitForPaused(dbg);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
@@ -20,21 +20,21 @@ async function waitForBreakpoint(dbg, lo
 function getBreakpoints(dbg) {
   const breakpoints = dbg.selectors.getBreakpoints(dbg.getState());
   return breakpoints.valueSeq().toJS();
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-minified.html");
 
-  dump(`>> meh`)
+  dump(`>> meh`);
 
   await navigate(dbg, "sourcemaps-reload/doc-sourcemaps-reload.html", "v1");
 
-  dump(`>> select v1`)
+  dump(`>> select v1`);
   await selectSource(dbg, "v1");
   await addBreakpoint(dbg, "v1", 6);
   let breakpoint = getBreakpoints(dbg)[0];
   is(breakpoint.location.line, 6);
 
   let syncBp = waitForDispatch(dbg, "SYNC_BREAKPOINT");
   await reload(dbg);
 
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reloading.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reloading.js
@@ -7,25 +7,30 @@ async function waitForBreakpointCount(db
     dbg,
     state => dbg.selectors.getBreakpoints(state).size === count
   );
 }
 
 add_task(async function() {
   // NOTE: the CORS call makes the test run times inconsistent
   const dbg = await initDebugger("doc-sourcemaps.html");
-  const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint, getBreakpoints },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
   ok(true, "Original sources exist");
   const entrySrc = findSource(dbg, "entry.js");
 
   await selectSource(dbg, entrySrc);
   ok(
-    getCM(dbg).getValue().includes("window.keepMeAlive"),
+    getCM(dbg)
+      .getValue()
+      .includes("window.keepMeAlive"),
     "Original source text loaded correctly"
   );
 
   // Test that breakpoint sliding is not attempted. The breakpoint
   // should not move anywhere.
   await addBreakpoint(dbg, entrySrc, 13);
   is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
 
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
@@ -1,17 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests loading sourcemapped sources, setting breakpoints, and
 // stepping in them.
 requestLongerTimeout(2);
 
 function assertBreakpointExists(dbg, source, line) {
-  const { selectors: { getBreakpoint }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint },
+    getState
+  } = dbg;
 
   ok(
     getBreakpoint(getState(), { sourceId: source.id, line }),
     "Breakpoint has correct line"
   );
 }
 
 function assertEditorBreakpoint(dbg, line, shouldExist) {
@@ -32,17 +35,20 @@ function getLineEl(dbg, line) {
 
 function clickGutter(dbg, line) {
   clickElement(dbg, "gutter", line);
 }
 
 add_task(async function() {
   // NOTE: the CORS call makes the test run times inconsistent
   const dbg = await initDebugger("doc-sourcemaps.html");
-  const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint, getBreakpoints },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
   ok(true, "Original sources exist");
   const bundleSrc = findSource(dbg, "bundle.js");
 
   await selectSource(dbg, bundleSrc);
 
   await clickGutter(dbg, 13);
@@ -52,17 +58,19 @@ add_task(async function() {
   await clickGutter(dbg, 13);
   await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
   is(getBreakpoints(getState()).size, 0, "No breakpoints exists");
 
   const entrySrc = findSource(dbg, "entry.js");
 
   await selectSource(dbg, entrySrc);
   ok(
-    getCM(dbg).getValue().includes("window.keepMeAlive"),
+    getCM(dbg)
+      .getValue()
+      .includes("window.keepMeAlive"),
     "Original source text loaded correctly"
   );
 
   // Test breaking on a breakpoint
   await addBreakpoint(dbg, "entry.js", 15);
   is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
   assertBreakpointExists(dbg, entrySrc, 15);
 
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps2.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps2.js
@@ -14,17 +14,20 @@ function assertBpInGutter(dbg, lineNumbe
 
 // Tests loading sourcemapped sources, setting breakpoints, and
 // stepping in them.
 
 // This source map does not have source contents, so it's fetched separately
 add_task(async function() {
   // NOTE: the CORS call makes the test run times inconsistent
   const dbg = await initDebugger("doc-sourcemaps2.html");
-  const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint, getBreakpoints },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, "main.js", "main.min.js");
 
   ok(true, "Original sources exist");
   const mainSrc = findSource(dbg, "main.js");
 
   await selectSource(dbg, mainSrc);
 
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps3.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps3.js
@@ -6,17 +6,20 @@
 requestLongerTimeout(2);
 
 // This source map does not have source contents, so it's fetched separately
 add_task(async function() {
   // NOTE: the CORS call makes the test run times inconsistent
   await pushPref("devtools.debugger.features.map-scopes", true);
 
   const dbg = await initDebugger("doc-sourcemaps3.html");
-  const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint, getBreakpoints },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, "bundle.js", "sorted.js", "test.js");
 
   ok(true, "Original sources exist");
   const sortedSrc = findSource(dbg, "sorted.js");
 
   await selectSource(dbg, sortedSrc);
 
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sources-named-eval.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sources-named-eval.js
@@ -14,17 +14,20 @@ async function waitForSourceCount(dbg, i
 function getLabel(dbg, index) {
   return findElement(dbg, "sourceNode", index)
     .textContent.trim()
     .replace(/^[\s\u200b]*/g, "");
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-sources.html");
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
 
   ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
     content.eval("window.evaledFunc = function() {} //# sourceURL=evaled.js");
   });
 
   await waitForSourceCount(dbg, 3);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sources.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sources.js
@@ -19,17 +19,20 @@ async function assertSourceCount(dbg, co
 function getLabel(dbg, index) {
   return findElement(dbg, "sourceNode", index)
     .textContent.trim()
     .replace(/^[\s\u200b]*/g, "");
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-sources.html");
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
 
   // Expand nodes and make sure more sources appear.
   await assertSourceCount(dbg, 2);
   await clickElement(dbg, "sourceDirectoryLabel", 2);
 
   await assertSourceCount(dbg, 7);
@@ -44,20 +47,17 @@ add_task(async function() {
   // Ensure the source file clicked is now focused
   await waitForElementWithSelector(dbg, ".sources-list .focused");
 
   const focusedNode = findElementWithSelector(dbg, ".sources-list .focused");
   const fourthNode = findElement(dbg, "sourceNode", 4);
   const selectedSource = getSelectedSource(getState()).get("url");
 
   ok(fourthNode.classList.contains("focused"), "4th node is focused");
-  ok(
-    selectedSource.includes("nested-source.js"),
-    "nested-source is selected"
-  );
+  ok(selectedSource.includes("nested-source.js"), "nested-source is selected");
 
   await waitForSelectedSource(dbg, "nested-source");
 
   // Make sure new sources appear in the list.
   ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
     const script = content.document.createElement("script");
     script.src = "math.min.js";
     content.document.body.appendChild(script);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
- // This test can be really slow on debug platforms
- requestLongerTimeout(5);
+// This test can be really slow on debug platforms
+requestLongerTimeout(5);
 
 add_task(async function test() {
   const dbg = await initDebugger("big-sourcemap.html", "big-sourcemap");
   invokeInTab("hitDebugStatement");
   await waitForPaused(dbg, "bundle.js");
 
   await stepIn(dbg);
   await stepIn(dbg);
--- a/devtools/client/debugger/new/test/mochitest/examples/doc-preview.html
+++ b/devtools/client/debugger/new/test/mochitest/examples/doc-preview.html
@@ -11,13 +11,10 @@
   <body>
     <script src="preview.js"></script>
     <script>
       // This inline script allows this HTML page to show up as a
       // source. It also needs to introduce a new global variable so
       // it's not immediately garbage collected.
       inline_script = function () { var x = 5; };
     </script>
-
-    <button onclick="empties()">Empties</button>
-    <button onclick="smalls()">Smalls</button>
   </body>
 </html>
--- a/devtools/client/debugger/new/test/mochitest/head.js
+++ b/devtools/client/debugger/new/test/mochitest/head.js
@@ -35,17 +35,18 @@
 // shared-head.js handles imports, constants, and utility functions
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
   this
 );
 
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/debugger/new/test/mochitest/helpers.js",
-  this);
+  this
+);
 
 const EXAMPLE_URL =
   "http://example.com/browser/devtools/client/debugger/new/test/mochitest/examples/";
 
 Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", true);
 
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -151,17 +151,20 @@ function waitForState(dbg, predicate, ms
  *
  * @memberof mochitest/waits
  * @param {Object} dbg
  * @param {Array} sources
  * @return {Promise}
  * @static
  */
 async function waitForSources(dbg, ...sources) {
-  const { selectors: { getSources }, store } = dbg;
+  const {
+    selectors: { getSources },
+    store
+  } = dbg;
   if (sources.length === 0) {
     return Promise.resolve();
   }
 
   info(`Waiting on sources: ${sources.join(", ")}`);
   await Promise.all(
     sources.map(url => {
       if (!sourceExists(dbg, url)) {
@@ -206,17 +209,16 @@ async function waitForElementWithSelecto
   await waitUntil(() => findElementWithSelector(dbg, selector));
   return findElementWithSelector(dbg, selector);
 }
 
 function waitForSelectedSource(dbg, url) {
   return waitForState(
     dbg,
     state => {
-
       const source = dbg.selectors.getSelectedSource(state);
       const isLoaded = source && sourceUtils.isLoaded(source);
       if (!isLoaded) {
         return false;
       }
 
       if (!url) {
         return true;
@@ -254,32 +256,38 @@ function assertNotPaused(dbg) {
  * @memberof mochitest/asserts
  * @static
  */
 function assertPaused(dbg) {
   ok(isPaused(dbg), "client is paused");
 }
 
 function getVisibleSelectedFrameLine(dbg) {
-  const { selectors: { getVisibleSelectedFrame }, getState } = dbg;
+  const {
+    selectors: { getVisibleSelectedFrame },
+    getState
+  } = dbg;
   const frame = getVisibleSelectedFrame(getState());
   return frame && frame.location.line;
 }
 
 /**
  * Assert that the debugger is paused at the correct location.
  *
  * @memberof mochitest/asserts
  * @param {Object} dbg
  * @param {String} source
  * @param {Number} line
  * @static
  */
 function assertPausedLocation(dbg) {
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
 
   ok(
     isSelectedFrameSelected(dbg, getState()),
     "top frame's source is selected"
   );
 
   // Check the pause location
   const pauseLine = getVisibleSelectedFrameLine(dbg);
@@ -339,17 +347,20 @@ function assertDebugLine(dbg, line) {
  *
  * @memberof mochitest/asserts
  * @param {Object} dbg
  * @param {String} source
  * @param {Number} line
  * @static
  */
 function assertHighlightLocation(dbg, source, line) {
-  const { selectors: { getSelectedSource }, getState } = dbg;
+  const {
+    selectors: { getSelectedSource },
+    getState
+  } = dbg;
   source = findSource(dbg, source);
 
   // Check the selected source
   is(
     getSelectedSource(getState()).get("url"),
     source.url,
     "source url is correct"
   );
@@ -376,17 +387,20 @@ function assertHighlightLocation(dbg, so
 /**
  * Returns boolean for whether the debugger is paused.
  *
  * @memberof mochitest/asserts
  * @param {Object} dbg
  * @static
  */
 function isPaused(dbg) {
-  const { selectors: { isPaused }, getState } = dbg;
+  const {
+    selectors: { isPaused },
+    getState
+  } = dbg;
   return !!isPaused(getState());
 }
 
 async function waitForLoadedScopes(dbg) {
   const scopes = await waitForElement(dbg, "scopes");
   // Since scopes auto-expand, we can assume they are loaded when there is a tree node
   // with the aria-level attribute equal to "2".
   await waitUntil(() => scopes.querySelector(`.tree-node[aria-level="2"]`));
@@ -682,18 +696,18 @@ async function reload(dbg, ...sources) {
  * @memberof mochitest/actions
  * @param {Object} dbg
  * @param {String} url
  * @param {Array} sources
  * @return {Promise}
  * @static
  */
 async function navigate(dbg, url, ...sources) {
-  info(`Navigating to ${url}`)
-  const navigated =  waitForDispatch(dbg, "NAVIGATE");
+  info(`Navigating to ${url}`);
+  const navigated = waitForDispatch(dbg, "NAVIGATE");
   await dbg.client.navigate(url);
   await navigated;
   return waitForSources(dbg, ...sources);
 }
 
 /**
  * Adds a breakpoint to a source at line/col.
  *
@@ -715,17 +729,20 @@ function addBreakpoint(dbg, source, line
 function disableBreakpoint(dbg, source, line, column) {
   source = findSource(dbg, source);
   const sourceId = source.id;
   dbg.actions.disableBreakpoint({ sourceId, line, column });
   return waitForDispatch(dbg, "DISABLE_BREAKPOINT");
 }
 
 async function loadAndAddBreakpoint(dbg, filename, line, column) {
-  const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
+  const {
+    selectors: { getBreakpoint, getBreakpoints },
+    getState
+  } = dbg;
 
   await waitForSources(dbg, filename);
 
   ok(true, "Original sources exist");
   const source = findSource(dbg, filename);
 
   await selectSource(dbg, source);
 
@@ -736,18 +753,27 @@ async function loadAndAddBreakpoint(dbg,
   ok(
     getBreakpoint(getState(), { sourceId: source.id, line, column }),
     `Breakpoint has correct line ${line}, column ${column}`
   );
 
   return source;
 }
 
-async function invokeWithBreakpoint(dbg, fnName, filename, { line, column }, handler) {
-  const { selectors: { getBreakpoints }, getState } = dbg;
+async function invokeWithBreakpoint(
+  dbg,
+  fnName,
+  filename,
+  { line, column },
+  handler
+) {
+  const {
+    selectors: { getBreakpoints },
+    getState
+  } = dbg;
 
   const source = await loadAndAddBreakpoint(dbg, filename, line, column);
 
   const invokeResult = invokeInTab(fnName);
 
   let invokeFailed = await Promise.race([
     waitForPaused(dbg),
     invokeResult.then(() => new Promise(() => {}), () => true)
@@ -998,17 +1024,17 @@ const selectors = {
   callStackHeader: ".call-stack-pane ._header",
   callStackBody: ".call-stack-pane .pane",
   expressionNode: i =>
     `.expressions-list .expression-container:nth-child(${i}) .object-label`,
   expressionValue: i =>
     `.expressions-list .expression-container:nth-child(${i}) .object-delimiter + *`,
   expressionClose: i =>
     `.expressions-list .expression-container:nth-child(${i}) .close`,
-  expressionInput: '.expressions-list  input.input-expression',
+  expressionInput: ".expressions-list  input.input-expression",
   expressionNodes: ".expressions-list .tree-node",
   scopesHeader: ".scopes-pane ._header",
   breakpointItem: i => `.breakpoints-list .breakpoint:nth-of-type(${i})`,
   breakpointItems: `.breakpoints-list .breakpoint`,
   scopes: ".scopes-list",
   scopeNode: i => `.scopes-list .tree-node:nth-child(${i}) .object-label`,
   scopeValue: i =>
     `.scopes-list .tree-node:nth-child(${i}) .object-delimiter + *`,
@@ -1042,17 +1068,17 @@ const selectors = {
   fileMatch: ".managed-tree .result",
   popup: ".popover",
   tooltip: ".tooltip",
   previewPopup: ".preview-popup",
   outlineItem: i =>
     `.outline-list__element:nth-child(${i}) .function-signature`,
   outlineItems: ".outline-list__element",
   conditionalPanelInput: ".conditional-breakpoint-panel input",
-  searchField: ".search-field",
+  searchField: ".search-field"
 };
 
 function getSelector(elementName, ...args) {
   let selector = selectors[elementName];
   if (!selector) {
     throw new Error(`The selector ${elementName} is not defined`);
   }
 
@@ -1163,21 +1189,20 @@ function getScopeLabel(dbg, index) {
   return findElement(dbg, "scopeNode", index).innerText;
 }
 
 function getScopeValue(dbg, index) {
   return findElement(dbg, "scopeValue", index).innerText;
 }
 
 function toggleObjectInspectorNode(node) {
-
   const objectInspector = node.closest(".object-inspector");
   const properties = objectInspector.querySelectorAll(".node").length;
 
-  log(`Toggling node ${node.innerText}`)
+  log(`Toggling node ${node.innerText}`);
   node.click();
   return waitUntil(
     () => objectInspector.querySelectorAll(".node").length !== properties
   );
 }
 
 function getCM(dbg) {
   const el = dbg.win.document.querySelector(".CodeMirror");
@@ -1259,17 +1284,17 @@ async function assertPreviewPopup(
 ) {
   await tryHovering(dbg, line, column, "popup");
 
   const preview = dbg.selectors.getPreview(dbg.getState());
 
   const properties =
     preview.result.preview.ownProperties || preview.result.preview.items;
   const property = properties[field];
-  const propertyValue = property.value || property
+  const propertyValue = property.value || property;
 
   is(`${propertyValue}`, value, "Preview.result");
   is(preview.updating, false, "Preview.updating");
   is(preview.expression, expression, "Preview.expression");
 }
 
 async function assertPreviews(dbg, previews) {
   for (const { line, column, expression, result, fields } of previews) {
@@ -1289,9 +1314,9 @@ async function assertPreviews(dbg, previ
       await assertPreviewTextValue(dbg, line, column, {
         expression,
         text: result
       });
     }
 
     dbg.actions.clearPreview();
   }
-}
\ No newline at end of file
+}
--- a/devtools/client/locales/en-US/debugger.properties
+++ b/devtools/client/locales/en-US/debugger.properties
@@ -92,19 +92,19 @@ pauseButtonItem=Pause on Next Statement
 # LOCALIZATION NOTE (ignoreExceptionsItem): The pause on exceptions button description
 # when the debugger will not pause on exceptions.
 ignoreExceptionsItem=Ignore exceptions
 
 # LOCALIZATION NOTE (pauseOnUncaughtExceptionsItem): The pause on exceptions dropdown
 # item shown when a user is adding a new breakpoint.
 pauseOnUncaughtExceptionsItem=Pause on uncaught exceptions
 
-# LOCALIZATION NOTE (pauseOnExceptionsItem2): The pause on exceptions checkbox description
+# LOCALIZATION NOTE (pauseOnExceptionsItem): The pause on exceptions checkbox description
 # when the debugger will pause on all exceptions.
-pauseOnExceptionsItem2=Pause on exceptions
+pauseOnExceptionsItem=Pause on exceptions
 
 # LOCALIZATION NOTE (ignoreCaughtExceptionsItem): The pause on exceptions checkbox description
 # when the debugger will not pause on any caught exception
 ignoreCaughtExceptionsItem=Ignore caught exceptions
 
 # LOCALIZATION NOTE (pauseOnCaughtExceptionsItem): The pause on exceptions checkbox description
 # when the debugger should pause on caught exceptions
 pauseOnCaughtExceptionsItem=Pause on caught exceptions
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -1607,17 +1607,19 @@ var _extends = Object.assign || function
 
 const client = __webpack_require__(3665);
 const loadProperties = __webpack_require__(3666);
 const node = __webpack_require__(3667);
 const { nodeIsError, nodeIsPrimitive } = node;
 const selection = __webpack_require__(3698);
 
 const { MODE } = __webpack_require__(3645);
-const { REPS: { Rep, Grip } } = __webpack_require__(3647);
+const {
+  REPS: { Rep, Grip }
+} = __webpack_require__(3647);
 
 
 function shouldRenderRootsInReps(roots) {
   if (roots.length > 1) {
     return false;
   }
 
   const root = roots[0];
@@ -3079,17 +3081,19 @@ function nodeHasAllEntriesInPreview(item
   return entries ? entries.length === size : items.length === length;
 }
 
 function nodeNeedsNumericalBuckets(item) {
   return nodeSupportsNumericalBucketing(item) && getNumericalPropertiesCount(item) > MAX_NUMERICAL_PROPERTIES;
 }
 
 function makeNodesForPromiseProperties(item) {
-  const { promiseState: { reason, value, state } } = getValue(item);
+  const {
+    promiseState: { reason, value, state }
+  } = getValue(item);
 
   const properties = [];
 
   if (state) {
     properties.push(createNode({
       parent: item,
       name: "<state>",
       contents: { value: state },
--- a/devtools/client/shared/source-map/index.js
+++ b/devtools/client/shared/source-map/index.js
@@ -425,17 +425,19 @@ function isSlowBuffer (obj) {
 
 const {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId
 } = __webpack_require__(3652);
 
-const { workerUtils: { WorkerDispatcher } } = __webpack_require__(3651);
+const {
+  workerUtils: { WorkerDispatcher }
+} = __webpack_require__(3651);
 
 const dispatcher = new WorkerDispatcher();
 
 const getOriginalURLs = dispatcher.task("getOriginalURLs");
 const getGeneratedRanges = dispatcher.task("getGeneratedRanges", {
   queue: true
 });
 const getGeneratedLocation = dispatcher.task("getGeneratedLocation", {
--- a/devtools/client/shared/source-map/worker.js
+++ b/devtools/client/shared/source-map/worker.js
@@ -1980,17 +1980,19 @@ const {
   getOriginalSourceText,
   getLocationScopes,
   hasMappedSource,
   applySourceMap
 } = __webpack_require__(3710);
 
 const { clearSourceMaps } = __webpack_require__(3704);
 
-const { workerUtils: { workerHandler } } = __webpack_require__(3651);
+const {
+  workerUtils: { workerHandler }
+} = __webpack_require__(3651);
 
 // The interface is implemented in source-map to be
 // easier to unit test.
 self.onmessage = workerHandler({
   getOriginalURLs,
   getGeneratedRanges,
   getGeneratedLocation,
   getAllGeneratedLocations,
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -129,16 +129,28 @@ static const RedirEntry kRedirMap[] = {
     "webrtc", "chrome://global/content/aboutwebrtc/aboutWebrtc.html",
     nsIAboutModule::ALLOW_SCRIPT
   },
   {
     "printpreview", "about:blank",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT |
     nsIAboutModule::URI_CAN_LOAD_IN_CHILD
+  },
+  {
+    "crashparent", "about:blank",
+    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+    nsIAboutModule::HIDE_FROM_ABOUTABOUT
+  },
+  {
+    "crashcontent", "about:blank",
+    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+    nsIAboutModule::HIDE_FROM_ABOUTABOUT |
+    nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
+    nsIAboutModule::URI_MUST_LOAD_IN_CHILD
   }
 };
 static const int kRedirTotal = mozilla::ArrayLength(kRedirMap);
 
 NS_IMETHODIMP
 nsAboutRedirector::NewChannel(nsIURI* aURI,
                               nsILoadInfo* aLoadInfo,
                               nsIChannel** aResult)
@@ -149,16 +161,24 @@ nsAboutRedirector::NewChannel(nsIURI* aU
 
   nsAutoCString path;
   nsresult rv = NS_GetAboutModuleName(aURI, path);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (XRE_IsParentProcess() && path.EqualsASCII("crashparent")) {
+    MOZ_CRASH("Crash via about:crashparent");
+  }
+
+  if (XRE_IsContentProcess() && path.EqualsASCII("crashcontent")) {
+    MOZ_CRASH("Crash via about:crashcontent");
+  }
+
   for (int i = 0; i < kRedirTotal; i++) {
     if (!strcmp(path.get(), kRedirMap[i].id)) {
       nsCOMPtr<nsIChannel> tempChannel;
       nsCOMPtr<nsIURI> tempURI;
       rv = NS_NewURI(getter_AddRefs(tempURI), kRedirMap[i].url);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -173,16 +173,18 @@ const mozilla::Module::ContractIDEntry k
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "about", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "addons", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "buildconfig", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "checkerboard", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "config", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
 #ifdef MOZ_CRASHREPORTER
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashes", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
 #endif
+  { NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashparent", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
+  { NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashcontent", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "credits", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "license", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "memory", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "mozilla", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "networking", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "performance", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
--- a/docshell/shistory/nsSHEntryShared.cpp
+++ b/docshell/shistory/nsSHEntryShared.cpp
@@ -242,50 +242,23 @@ nsSHEntryShared::RemoveFromBFCacheAsync(
 nsresult
 nsSHEntryShared::GetID(uint64_t* aID)
 {
   *aID = mID;
   return NS_OK;
 }
 
 void
-nsSHEntryShared::NodeWillBeDestroyed(const nsINode* aNode)
-{
-  NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
-}
-
-void
-nsSHEntryShared::CharacterDataWillChange(nsIContent* aContent,
-                                         const CharacterDataChangeInfo&)
-{
-}
-
-void
 nsSHEntryShared::CharacterDataChanged(nsIContent* aContent,
                                       const CharacterDataChangeInfo&)
 {
   RemoveFromBFCacheAsync();
 }
 
 void
-nsSHEntryShared::AttributeWillChange(dom::Element* aContent,
-                                     int32_t aNameSpaceID,
-                                     nsAtom* aAttribute,
-                                     int32_t aModType,
-                                     const nsAttrValue* aNewValue)
-{
-}
-
-void
-nsSHEntryShared::NativeAnonymousChildListChange(nsIContent* aContent,
-                                                bool aIsRemove)
-{
-}
-
-void
 nsSHEntryShared::AttributeChanged(dom::Element* aElement,
                                   int32_t aNameSpaceID,
                                   nsAtom* aAttribute,
                                   int32_t aModType,
                                   const nsAttrValue* aOldValue)
 {
   RemoveFromBFCacheAsync();
 }
@@ -303,13 +276,8 @@ nsSHEntryShared::ContentInserted(nsICont
 }
 
 void
 nsSHEntryShared::ContentRemoved(nsIContent* aChild,
                                 nsIContent* aPreviousSibling)
 {
   RemoveFromBFCacheAsync();
 }
-
-void
-nsSHEntryShared::ParentChainChanged(nsIContent* aContent)
-{
-}
--- a/docshell/shistory/nsSHEntryShared.h
+++ b/docshell/shistory/nsSHEntryShared.h
@@ -7,19 +7,19 @@
 #ifndef nsSHEntryShared_h__
 #define nsSHEntryShared_h__
 
 #include "nsAutoPtr.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsExpirationTracker.h"
 #include "nsIBFCacheEntry.h"
-#include "nsIMutationObserver.h"
 #include "nsRect.h"
 #include "nsString.h"
+#include "nsStubMutationObserver.h"
 #include "nsWeakPtr.h"
 
 #include "mozilla/Attributes.h"
 
 class nsSHEntry;
 class nsISHEntry;
 class nsIDocument;
 class nsIContentViewer;
@@ -31,28 +31,34 @@ class nsIMutableArray;
 // A document may have multiple SHEntries, either due to hash navigations or
 // calls to history.pushState.  SHEntries corresponding to the same document
 // share many members; in particular, they share state related to the
 // back/forward cache.
 //
 // nsSHEntryShared is the vehicle for this sharing.
 class nsSHEntryShared final
   : public nsIBFCacheEntry
-  , public nsIMutationObserver
+  , public nsStubMutationObserver
 {
 public:
   static void EnsureHistoryTracker();
   static void Shutdown();
 
   nsSHEntryShared();
 
   NS_DECL_ISUPPORTS
-  NS_DECL_NSIMUTATIONOBSERVER
   NS_DECL_NSIBFCACHEENTRY
 
+  // The nsIMutationObserver bits we actually care about.
+  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
   nsExpirationState *GetExpirationState() { return &mExpirationState; }
 
 private:
   ~nsSHEntryShared();
 
   friend class nsSHEntry;
 
   static already_AddRefed<nsSHEntryShared> Duplicate(nsSHEntryShared* aEntry);
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -560,17 +560,17 @@ CandidateFinder::OrderedCandidates()
       nsTArray<nsCOMPtr<Element>> rval({ Move(iter.Data()) });
       iter.Remove();
       return rval;
     }
   }
 
   nsTArray<nsCOMPtr<Element>> orderedElements(mCandidates.Count());
   for (Element* child = mDoc->GetFirstElementChild(); child; child = child->GetNextElementSibling()) {
-    if (!Traverse(child->AsElement(), orderedElements)) {
+    if (!Traverse(child, orderedElements)) {
       break;
     }
   }
 
   return orderedElements;
 }
 
 bool
@@ -643,77 +643,36 @@ nsISupports* CustomElementRegistry::GetP
 }
 
 DocGroup*
 CustomElementRegistry::GetDocGroup() const
 {
   return mWindow ? mWindow->GetDocGroup() : nullptr;
 }
 
-static const char* kLifeCycleCallbackNames[] = {
-  "connectedCallback",
-  "disconnectedCallback",
-  "adoptedCallback",
-  "attributeChangedCallback"
-};
-
-static void
-CheckLifeCycleCallbacks(JSContext* aCx,
-                        JS::Handle<JSObject*> aConstructor,
-                        ErrorResult& aRv)
-{
-  for (size_t i = 0; i < ArrayLength(kLifeCycleCallbackNames); ++i) {
-    const char* callbackName = kLifeCycleCallbackNames[i];
-    JS::Rooted<JS::Value> callbackValue(aCx);
-    if (!JS_GetProperty(aCx, aConstructor, callbackName, &callbackValue)) {
-      aRv.StealExceptionFromJSContext(aCx);
-      return;
-    }
-    if (!callbackValue.isUndefined()) {
-      if (!callbackValue.isObject()) {
-        aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_ConvertASCIItoUTF16(callbackName));
-        return;
-      }
-      JS::Rooted<JSObject*> callback(aCx, &callbackValue.toObject());
-      if (!JS::IsCallable(callback)) {
-        aRv.ThrowTypeError<MSG_NOT_CALLABLE>(NS_ConvertASCIItoUTF16(callbackName));
-        return;
-      }
-    }
-  }
-}
-
 // https://html.spec.whatwg.org/multipage/scripting.html#element-definition
 void
-CustomElementRegistry::Define(const nsAString& aName,
+CustomElementRegistry::Define(JSContext* aCx,
+                              const nsAString& aName,
                               Function& aFunctionConstructor,
                               const ElementDefinitionOptions& aOptions,
                               ErrorResult& aRv)
 {
-  aRv.MightThrowJSException();
-
-  AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(mWindow))) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  JSContext *cx = jsapi.cx();
   // Note: No calls that might run JS or trigger CC before this point, or
   // there's a (vanishingly small) chance of our constructor being nulled
   // before we access it.
-  JS::Rooted<JSObject*> constructor(cx, aFunctionConstructor.CallableOrNull());
+  JS::Rooted<JSObject*> constructor(aCx, aFunctionConstructor.CallableOrNull());
 
   /**
    * 1. If IsConstructor(constructor) is false, then throw a TypeError and abort
    *    these steps.
    */
   // For now, all wrappers are constructable if they are callable. So we need to
   // unwrap constructor to check it is really constructable.
-  JS::Rooted<JSObject*> constructorUnwrapped(cx, js::CheckedUnwrap(constructor));
+  JS::Rooted<JSObject*> constructorUnwrapped(aCx, js::CheckedUnwrap(constructor));
   if (!constructorUnwrapped) {
     // If the caller's compartment does not have permission to access the
     // unwrapped constructor then throw.
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   if (!JS::IsConstructor(constructorUnwrapped)) {
@@ -811,176 +770,148 @@ CustomElementRegistry::Define(const nsAS
    * 8. If this CustomElementRegistry's element definition is running flag is set,
    *    then throw a "NotSupportedError" DOMException and abort these steps.
    */
   if (mIsCustomDefinitionRunning) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 
-  JS::Rooted<JS::Value> constructorPrototype(cx);
-  nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks());
+  auto callbacksHolder = MakeUnique<LifecycleCallbacks>();
   nsTArray<RefPtr<nsAtom>> observedAttributes;
   { // Set mIsCustomDefinitionRunning.
     /**
      * 9. Set this CustomElementRegistry's element definition is running flag.
      */
     AutoSetRunningFlag as(this);
 
-    { // Enter constructor's realm.
-      /**
-       * 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
-       */
-      JSAutoRealm ar(cx, constructor);
-      // The .prototype on the constructor passed could be an "expando" of a
-      // wrapper. So we should get it from wrapper instead of the underlying
-      // object.
-      if (!JS_GetProperty(cx, constructor, "prototype", &constructorPrototype)) {
-        aRv.StealExceptionFromJSContext(cx);
-        return;
-      }
+    /**
+     * 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions.
+     */
+    // The .prototype on the constructor passed could be an "expando" of a
+    // wrapper. So we should get it from wrapper instead of the underlying
+    // object.
+    JS::Rooted<JS::Value> prototype(aCx);
+    if (!JS_GetProperty(aCx, constructor, "prototype", &prototype)) {
+      aRv.NoteJSContextException(aCx);
+      return;
+    }
 
-      /**
-       * 10.2. If Type(prototype) is not Object, then throw a TypeError exception.
-       */
-      if (!constructorPrototype.isObject()) {
-        aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("constructor.prototype"));
-        return;
-      }
-    } // Leave constructor's realm.
-
-    JS::Rooted<JSObject*> constructorProtoUnwrapped(
-      cx, js::CheckedUnwrap(&constructorPrototype.toObject()));
-    if (!constructorProtoUnwrapped) {
-      // If the caller's compartment does not have permission to access the
-      // unwrapped prototype then throw.
-      aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    /**
+     * 10.2. If Type(prototype) is not Object, then throw a TypeError exception.
+     */
+    if (!prototype.isObject()) {
+      aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("constructor.prototype"));
       return;
     }
 
-    { // Enter constructorProtoUnwrapped's compartment
-      JSAutoRealm ar(cx, constructorProtoUnwrapped);
+    /**
+     * 10.3. Let lifecycleCallbacks be a map with the four keys
+     *       "connectedCallback", "disconnectedCallback", "adoptedCallback", and
+     *       "attributeChangedCallback", each of which belongs to an entry whose
+     *       value is null.
+     * 10.4. For each of the four keys callbackName in lifecycleCallbacks:
+     *       1. Let callbackValue be Get(prototype, callbackName). Rethrow any
+     *          exceptions.
+     *       2. If callbackValue is not undefined, then set the value of the
+     *          entry in lifecycleCallbacks with key callbackName to the result
+     *          of converting callbackValue to the Web IDL Function callback type.
+     *          Rethrow any exceptions from the conversion.
+     */
+    if (!callbacksHolder->Init(aCx, prototype)) {
+      aRv.NoteJSContextException(aCx);
+      return;
+    }
 
-      /**
-       * 10.3. Let lifecycleCallbacks be a map with the four keys
-       *       "connectedCallback", "disconnectedCallback", "adoptedCallback", and
-       *       "attributeChangedCallback", each of which belongs to an entry whose
-       *       value is null.
-       * 10.4. For each of the four keys callbackName in lifecycleCallbacks:
-       *       1. Let callbackValue be Get(prototype, callbackName). Rethrow any
-       *          exceptions.
-       *       2. If callbackValue is not undefined, then set the value of the
-       *          entry in lifecycleCallbacks with key callbackName to the result
-       *          of converting callbackValue to the Web IDL Function callback type.
-       *          Rethrow any exceptions from the conversion.
-       */
-      // Will do the same checking for the life cycle callbacks from v0 spec.
-      CheckLifeCycleCallbacks(cx, constructorProtoUnwrapped, aRv);
-      if (aRv.Failed()) {
-        return;
-      }
+    /**
+     * 10.5. Let observedAttributes be an empty sequence<DOMString>.
+     * 10.6. If the value of the entry in lifecycleCallbacks with key
+     *       "attributeChangedCallback" is not null, then:
+     *       1. Let observedAttributesIterable be Get(constructor,
+     *          "observedAttributes"). Rethrow any exceptions.
+     *       2. If observedAttributesIterable is not undefined, then set
+     *          observedAttributes to the result of converting
+     *          observedAttributesIterable to a sequence<DOMString>. Rethrow
+     *          any exceptions from the conversion.
+     */
+    if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
+      JS::Rooted<JS::Value> observedAttributesIterable(aCx);
 
-      // Note: We call the init from the constructorProtoUnwrapped's compartment
-      //       here.
-      JS::RootedValue rootedv(cx, JS::ObjectValue(*constructorProtoUnwrapped));
-      if (!JS_WrapValue(cx, &rootedv) || !callbacksHolder->Init(cx, rootedv)) {
-        aRv.StealExceptionFromJSContext(cx);
+      if (!JS_GetProperty(aCx, constructor, "observedAttributes",
+                          &observedAttributesIterable)) {
+        aRv.NoteJSContextException(aCx);
         return;
       }
 
-      /**
-       * 10.5. Let observedAttributes be an empty sequence<DOMString>.
-       * 10.6. If the value of the entry in lifecycleCallbacks with key
-       *       "attributeChangedCallback" is not null, then:
-       *       1. Let observedAttributesIterable be Get(constructor,
-       *          "observedAttributes"). Rethrow any exceptions.
-       *       2. If observedAttributesIterable is not undefined, then set
-       *          observedAttributes to the result of converting
-       *          observedAttributesIterable to a sequence<DOMString>. Rethrow
-       *          any exceptions from the conversion.
-       */
-      if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
-        // Enter constructor's realm.
-        JSAutoRealm ar(cx, constructor);
-        JS::Rooted<JS::Value> observedAttributesIterable(cx);
+      if (!observedAttributesIterable.isUndefined()) {
+        if (!observedAttributesIterable.isObject()) {
+          aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
+          return;
+        }
 
-        if (!JS_GetProperty(cx, constructor, "observedAttributes",
-                            &observedAttributesIterable)) {
-          aRv.StealExceptionFromJSContext(cx);
+        JS::ForOfIterator iter(aCx);
+        if (!iter.init(observedAttributesIterable, JS::ForOfIterator::AllowNonIterable)) {
+          aRv.NoteJSContextException(aCx);
           return;
         }
 
-        if (!observedAttributesIterable.isUndefined()) {
-          if (!observedAttributesIterable.isObject()) {
-            aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
+        if (!iter.valueIsIterable()) {
+          aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
+          return;
+        }
+
+        JS::Rooted<JS::Value> attribute(aCx);
+        while (true) {
+          bool done;
+          if (!iter.next(&attribute, &done)) {
+            aRv.NoteJSContextException(aCx);
+            return;
+          }
+          if (done) {
+            break;
+          }
+
+          nsAutoString attrStr;
+          if (!ConvertJSValueToString(aCx, attribute, eStringify, eStringify, attrStr)) {
+            aRv.NoteJSContextException(aCx);
             return;
           }
 
-          JS::ForOfIterator iter(cx);
-          if (!iter.init(observedAttributesIterable, JS::ForOfIterator::AllowNonIterable)) {
-            aRv.StealExceptionFromJSContext(cx);
-            return;
-          }
-
-          if (!iter.valueIsIterable()) {
-            aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes"));
+          if (!observedAttributes.AppendElement(NS_Atomize(attrStr))) {
+            aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
             return;
           }
-
-          JS::Rooted<JS::Value> attribute(cx);
-          while (true) {
-            bool done;
-            if (!iter.next(&attribute, &done)) {
-              aRv.StealExceptionFromJSContext(cx);
-              return;
-            }
-            if (done) {
-              break;
-            }
-
-            nsAutoString attrStr;
-            if (!ConvertJSValueToString(cx, attribute, eStringify, eStringify, attrStr)) {
-              aRv.StealExceptionFromJSContext(cx);
-              return;
-            }
-
-            if (!observedAttributes.AppendElement(NS_Atomize(attrStr))) {
-              aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-              return;
-            }
-          }
         }
-      } // Leave constructor's realm.
-    } // Leave constructorProtoUnwrapped's compartment.
+      }
+    }
   } // Unset mIsCustomDefinitionRunning
 
   /**
    * 11. Let definition be a new custom element definition with name name,
    *     local name localName, constructor constructor, prototype prototype,
    *     observed attributes observedAttributes, and lifecycle callbacks
    *     lifecycleCallbacks.
    */
   // Associate the definition with the custom element.
   RefPtr<nsAtom> localNameAtom(NS_Atomize(localName));
-  LifecycleCallbacks* callbacks = callbacksHolder.forget();
 
   /**
    * 12. Add definition to this CustomElementRegistry.
    */
   if (!mConstructors.put(constructorUnwrapped, nameAtom)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   RefPtr<CustomElementDefinition> definition =
     new CustomElementDefinition(nameAtom,
                                 localNameAtom,
                                 &aFunctionConstructor,
                                 Move(observedAttributes),
-                                callbacks);
+                                Move(callbacksHolder));
 
   CustomElementDefinition* def = definition.get();
   mCustomDefinitions.Put(nameAtom, definition.forget());
 
   MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(),
              "Number of entries should be the same");
 
   /**
@@ -1387,19 +1318,19 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CustomElementDefinition, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CustomElementDefinition, Release)
 
 
 CustomElementDefinition::CustomElementDefinition(nsAtom* aType,
                                                  nsAtom* aLocalName,
                                                  Function* aConstructor,
                                                  nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
-                                                 LifecycleCallbacks* aCallbacks)
+                                                 UniquePtr<LifecycleCallbacks>&& aCallbacks)
   : mType(aType),
     mLocalName(aLocalName),
     mConstructor(new CustomElementConstructor(aConstructor)),
     mObservedAttributes(Move(aObservedAttributes)),
-    mCallbacks(aCallbacks)
+    mCallbacks(Move(aCallbacks))
 {
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -147,33 +147,33 @@ struct CustomElementDefinition
 {
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CustomElementDefinition)
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CustomElementDefinition)
 
   CustomElementDefinition(nsAtom* aType,
                           nsAtom* aLocalName,
                           Function* aConstructor,
                           nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
-                          mozilla::dom::LifecycleCallbacks* aCallbacks);
+                          UniquePtr<LifecycleCallbacks>&& aCallbacks);
 
   // The type (name) for this custom element, for <button is="x-foo"> or <x-foo>
   // this would be x-foo.
   RefPtr<nsAtom> mType;
 
   // The localname to (e.g. <button is=type> -- this would be button).
   RefPtr<nsAtom> mLocalName;
 
   // The custom element constructor.
   RefPtr<CustomElementConstructor> mConstructor;
 
   // The list of attributes that this custom element observes.
   nsTArray<RefPtr<nsAtom>> mObservedAttributes;
 
   // The lifecycle callbacks to call for this custom element.
-  UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
+  UniquePtr<LifecycleCallbacks> mCallbacks;
 
   // A construction stack. Use nullptr to represent an "already constructed marker".
   nsTArray<RefPtr<Element>> mConstructionStack;
 
   bool IsCustomBuiltIn()
   {
     return mType != mLocalName;
   }
@@ -505,17 +505,18 @@ private:
 
 public:
   nsISupports* GetParentObject() const;
 
   DocGroup* GetDocGroup() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  void Define(const nsAString& aName, Function& aFunctionConstructor,
+  void Define(JSContext* aCx, const nsAString& aName,
+              Function& aFunctionConstructor,
               const ElementDefinitionOptions& aOptions, ErrorResult& aRv);
 
   void Get(JSContext* cx, const nsAString& name,
            JS::MutableHandle<JS::Value> aRetVal);
 
   already_AddRefed<Promise> WhenDefined(const nsAString& aName, ErrorResult& aRv);
 
   // Chrome-only method that give JS an opportunity to only load the custom
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -504,31 +504,29 @@ private:
         (aTextNode->GetProperty(nsGkAtoms::textNodeDirectionalityMap));
     }
 
     return map;
   }
 
   static nsCheapSetOperator SetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aDir)
   {
-    MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element");
     aEntry->GetKey()->SetDirectionality(*reinterpret_cast<Directionality*>(aDir),
                                         true);
     return OpNext;
   }
 
   struct nsTextNodeDirectionalityMapAndElement
   {
     nsTextNodeDirectionalityMap* mMap;
     nsCOMPtr<nsINode> mNode;
   };
 
   static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aData)
   {
-    MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element");
     // run the downward propagation algorithm
     // and remove the text node from the map
     nsTextNodeDirectionalityMapAndElement* data =
       static_cast<nsTextNodeDirectionalityMapAndElement*>(aData);
     nsINode* oldTextNode = data->mNode;
     Element* rootNode = aEntry->GetKey();
     nsTextNode* newTextNode = nullptr;
     if (rootNode->GetParentNode() && rootNode->HasDirAuto()) {
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1959,16 +1959,20 @@ private:
    * @return the frame's client area
    */
   MOZ_CAN_RUN_SCRIPT nsRect GetClientAreaRect();
 
   MOZ_CAN_RUN_SCRIPT
   nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr,
                                      FlushType aFlushType = FlushType::Layout);
 
+  // Prevent people from doing pointless checks/casts on Element instances.
+  void IsElement() = delete;
+  void AsElement() = delete;
+
   // Data members
   EventStates mState;
   // Per-node data managed by Servo.
   //
   // There should not be data on nodes that are in the flattened tree, or
   // descendants of display: none elements.
   mozilla::ServoCell<ServoNodeData*> mServoData;
 };
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -7991,16 +7991,20 @@ nsIDocument::CollectDescendantDocuments(
 
 #ifdef DEBUG_bryner
 #define DEBUG_PAGE_CACHE
 #endif
 
 bool
 nsIDocument::CanSavePresentation(nsIRequest *aNewRequest)
 {
+  if (!IsBFCachingAllowed()) {
+    return false;
+  }
+
   if (EventHandlingSuppressed()) {
     return false;
   }
 
   // Do not allow suspended windows to be placed in the
   // bfcache.  This method is also used to verify a document
   // coming out of the bfcache is ok to restore, though.  So
   // we only want to block suspend windows that aren't also
@@ -11254,17 +11258,17 @@ nsIDocument::ApplyFullscreen(const Fulls
   while (true) {
     child->SetFullscreenRoot(fullScreenRootDoc);
     NS_ASSERTION(child->GetFullscreenRoot() == fullScreenRootDoc,
         "Fullscreen root should be set!");
     if (child == fullScreenRootDoc) {
       break;
     }
     nsIDocument* parent = child->GetParentDocument();
-    Element* element = parent->FindContentForSubDocument(child)->AsElement();
+    Element* element = parent->FindContentForSubDocument(child);
     if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) {
       changed.AppendElement(parent);
       child = parent;
     } else {
       // We've reached either the root, or a point in the doctree where the
       // new full-screen element container is the same as the previous
       // full-screen element's container. No more changes need to be made
       // to the full-screen stacks of documents further up the tree.
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -205,16 +205,20 @@ DOMInterfaces = {
     'nativeType': 'mozilla::BindingStyleRule',
 },
 
 'CSSStyleSheet': {
     'nativeType': 'mozilla::StyleSheet',
     'binaryNames': { 'ownerRule': 'DOMOwnerRule' },
 },
 
+'CustomElementRegistry': {
+    'implicitJSContext': ['define'],
+},
+
 'DedicatedWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
 },
 
 'DeviceAcceleration': {
     'headerFile': 'mozilla/dom/DeviceMotionEvent.h',
 },
 
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -529,17 +529,17 @@ HTMLSelectElement::GetOptionIndexAfter(n
 }
 
 int32_t
 HTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions)
 {
   int32_t listIndex = -1;
   HTMLOptionElement* optElement = HTMLOptionElement::FromNode(aOptions);
   if (optElement) {
-    mOptions->GetOptionIndex(optElement->AsElement(), 0, true, &listIndex);
+    mOptions->GetOptionIndex(optElement, 0, true, &listIndex);
     return listIndex;
   }
 
   listIndex = GetFirstChildOptionIndex(aOptions, 0, aOptions->GetChildCount());
 
   return listIndex;
 }
 
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -151,17 +151,17 @@ protected:
                           uint64_t epoch);
 
   void RunNotificationObserversTask();
   void QueueEntry(PerformanceEntry* aEntry);
 
   nsTObserverArray<PerformanceObserver*> mObservers;
 
 protected:
-  static const uint64_t kDefaultResourceTimingBufferSize = 150;
+  static const uint64_t kDefaultResourceTimingBufferSize = 250;
 
   // When kDefaultResourceTimingBufferSize is increased or removed, these should
   // be changed to use SegmentedVector
   AutoTArray<RefPtr<PerformanceEntry>, kDefaultResourceTimingBufferSize> mUserEntries;
   AutoTArray<RefPtr<PerformanceEntry>, kDefaultResourceTimingBufferSize> mResourceEntries;
 
   uint64_t mResourceTimingBufferSize;
   bool mPendingNotificationObserversTask;
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -81,16 +81,18 @@ static decltype(ImmGetCompositionStringW
                                              nullptr;
 static decltype(ImmSetCandidateWindow)* sImm32ImmSetCandidateWindowStub =
                                           nullptr;
 static decltype(ImmNotifyIME)* sImm32ImmNotifyIME = nullptr;
 static decltype(ImmAssociateContextEx)* sImm32ImmAssociateContextExStub =
                                           nullptr;
 static PluginInstanceChild* sCurrentPluginInstance = nullptr;
 static const HIMC sHookIMC = (const HIMC)0xefefefef;
+static bool sPopupMenuHookSet;
+static bool sSetWindowLongHookSet;
 
 using mozilla::gfx::SharedDIB;
 
 // Flash WM_USER message delay time for PostDelayedTask. Borrowed
 // from Chromium's web plugin delegate src. See 'flash msg throttling
 // helpers' section for details.
 const int kFlashWMUSERMessageThrottleDelayMs = 5;
 
@@ -1892,18 +1894,25 @@ PluginInstanceChild::SetWindowLongWHook(
         NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!");
     }
     return proc;
 }
 
 void
 PluginInstanceChild::HookSetWindowLongPtr()
 {
-    if (!(GetQuirks() & QUIRK_FLASH_HOOK_SETLONGPTR))
+    if (!(GetQuirks() & QUIRK_FLASH_HOOK_SETLONGPTR)) {
         return;
+    }
+
+    // Only pass through here once
+    if (sSetWindowLongHookSet) {
+        return;
+    }
+    sSetWindowLongHookSet = true;
 
     sUser32Intercept.Init("user32.dll");
 #ifdef _WIN64
     if (!sUser32SetWindowLongAHookStub)
         sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast<intptr_t>(SetWindowLongPtrAHook),
                                  (void**) &sUser32SetWindowLongAHookStub);
     if (!sUser32SetWindowLongWHookStub)
         sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast<intptr_t>(SetWindowLongPtrWHook),
@@ -1973,29 +1982,33 @@ PluginInstanceChild::TrackPopupHookProc(
   }
 
   return res;
 }
 
 void
 PluginInstanceChild::InitPopupMenuHook()
 {
-    if (!(GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
-        sUser32TrackPopupMenuStub)
+    if (!(GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK)) {
         return;
+    }
+
+    // Only pass through here once
+    if (sPopupMenuHookSet) {
+        return;
+    }
+    sPopupMenuHookSet = true;
 
     // Note, once WindowsDllInterceptor is initialized for a module,
     // it remains initialized for that particular module for it's
     // lifetime. Additional instances are needed if other modules need
     // to be hooked.
-    if (!sUser32TrackPopupMenuStub) {
-        sUser32Intercept.Init("user32.dll");
-        sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast<intptr_t>(TrackPopupHookProc),
-                                 (void**) &sUser32TrackPopupMenuStub);
-    }
+    sUser32Intercept.Init("user32.dll");
+    sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast<intptr_t>(TrackPopupHookProc),
+                             (void**) &sUser32TrackPopupMenuStub);
 }
 
 void
 PluginInstanceChild::CreateWinlessPopupSurrogate()
 {
     // already initialized
     if (mWinlessPopupSurrogateHWND)
         return;
--- a/dom/webidl/WebComponents.webidl
+++ b/dom/webidl/WebComponents.webidl
@@ -15,13 +15,13 @@ callback LifecycleDisconnectedCallback =
 callback LifecycleAdoptedCallback = void(Document? oldDocument,
                                          Document? newDocment);
 callback LifecycleAttributeChangedCallback = void(DOMString attrName,
                                                   DOMString? oldValue,
                                                   DOMString? newValue,
                                                   DOMString? namespaceURI);
 
 dictionary LifecycleCallbacks {
-  LifecycleConnectedCallback? connectedCallback;
-  LifecycleDisconnectedCallback? disconnectedCallback;
-  LifecycleAdoptedCallback? adoptedCallback;
-  LifecycleAttributeChangedCallback? attributeChangedCallback;
+  LifecycleConnectedCallback connectedCallback;
+  LifecycleDisconnectedCallback disconnectedCallback;
+  LifecycleAdoptedCallback adoptedCallback;
+  LifecycleAttributeChangedCallback attributeChangedCallback;
 };
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -5120,17 +5120,17 @@ HTMLEditRules::ConvertListType(Element* 
           return nullptr;
         }
       }
     }
     child = child->GetNextSibling();
   }
 
   if (aList->IsHTMLElement(aListType)) {
-    RefPtr<dom::Element> list = aList->AsElement();
+    RefPtr<dom::Element> list = aList;
     return list.forget();
   }
 
   return mHTMLEditor->ReplaceContainerWithTransaction(*aList, *aListType);
 }
 
 
 /**
@@ -7402,17 +7402,17 @@ HTMLEditRules::SplitParagraph(
   if (aNextBRNode && htmlEditor->IsVisibleBRElement(aNextBRNode)) {
     rv = htmlEditor->DeleteNodeWithTransaction(*aNextBRNode);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // Remove ID attribute on the paragraph from the existing right node.
-  rv = htmlEditor->RemoveAttributeWithTransaction(*aParentDivOrP.AsElement(),
+  rv = htmlEditor->RemoveAttributeWithTransaction(aParentDivOrP,
                                                   *nsGkAtoms::id);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We need to ensure to both paragraphs visible even if they are empty.
   // However, moz-<br> element isn't useful in this case because moz-<br>
   // elements will be ignored by PlaintextSerializer.  Additionally,
   // moz-<br> will be exposed as <br> with Element.innerHTML.  Therefore,
   // we can use normal <br> elements for placeholder in this case.
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -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/. */
 
 #ifndef js_HashTable_h
 #define js_HashTable_h
 
-#include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Casting.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/MemoryChecking.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/Opaque.h"
@@ -25,17 +24,17 @@
 #include "js/Utility.h"
 
 namespace js {
 
 class TempAllocPolicy;
 template <class> struct DefaultHasher;
 template <class, class> class HashMapEntry;
 namespace detail {
-    template <class T> class HashTableEntry;
+    template <typename T> class HashTableEntry;
     template <class T, class HashPolicy, class AllocPolicy> class HashTable;
 } // namespace detail
 
 /*****************************************************************************/
 
 // The "generation" of a hash table is an opaque value indicating the state of
 // modification of the hash table through its lifetime.  If the generation of
 // a hash table compares equal at times T1 and T2, then lookups in the hash
@@ -768,94 +767,104 @@ class HashMapEntry
     HashMapEntry(const HashMapEntry&) = delete;
     void operator=(const HashMapEntry&) = delete;
 };
 
 } // namespace js
 
 namespace mozilla {
 
-template <typename T>
-struct IsPod<js::detail::HashTableEntry<T> > : IsPod<T> {};
-
 template <typename K, typename V>
 struct IsPod<js::HashMapEntry<K, V> >
   : IntegralConstant<bool, IsPod<K>::value && IsPod<V>::value>
 {};
 
 } // namespace mozilla
 
 namespace js {
 
 namespace detail {
 
 template <class T, class HashPolicy, class AllocPolicy>
 class HashTable;
 
-template <class T>
+template <typename T>
 class HashTableEntry
 {
-    template <class, class, class> friend class HashTable;
-    typedef typename mozilla::RemoveConst<T>::Type NonConstT;
-
-    HashNumber keyHash;
-    mozilla::AlignedStorage2<NonConstT> mem;
+  private:
+    using NonConstT = typename mozilla::RemoveConst<T>::Type;
 
     static const HashNumber sFreeKey = 0;
     static const HashNumber sRemovedKey = 1;
     static const HashNumber sCollisionBit = 1;
 
+    HashNumber keyHash = sFreeKey;
+    alignas(NonConstT) unsigned char valueData_[sizeof(NonConstT)];
+
+  private:
+    template <class, class, class> friend class HashTable;
+
+    // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
+    // -Werror compile error) to reinterpret_cast<> |valueData_| to |T*|, even
+    // through |void*|.  Placing the latter cast in these separate functions
+    // breaks the chain such that affected GCC versions no longer warn/error.
+    void* rawValuePtr() { return valueData_; }
+
     static bool isLiveHash(HashNumber hash)
     {
         return hash > sRemovedKey;
     }
 
     HashTableEntry(const HashTableEntry&) = delete;
     void operator=(const HashTableEntry&) = delete;
-    ~HashTableEntry() = delete;
+
+    NonConstT* valuePtr() { return reinterpret_cast<NonConstT*>(rawValuePtr()); }
 
     void destroyStoredT() {
-        mem.addr()->~T();
-        MOZ_MAKE_MEM_UNDEFINED(mem.addr(), sizeof(*mem.addr()));
+        NonConstT* ptr = valuePtr();
+        ptr->~T();
+        MOZ_MAKE_MEM_UNDEFINED(ptr, sizeof(*ptr));
     }
 
   public:
-    // NB: HashTableEntry is treated as a POD: no constructor or destructor calls.
+    HashTableEntry() = default;
 
-    void destroyIfLive() {
+    ~HashTableEntry() {
         if (isLive())
             destroyStoredT();
+
+        MOZ_MAKE_MEM_UNDEFINED(this, sizeof(*this));
     }
 
     void destroy() {
         MOZ_ASSERT(isLive());
         destroyStoredT();
     }
 
     void swap(HashTableEntry* other) {
         if (this == other)
             return;
         MOZ_ASSERT(isLive());
         if (other->isLive()) {
-            mozilla::Swap(*mem.addr(), *other->mem.addr());
+            mozilla::Swap(*valuePtr(), *other->valuePtr());
         } else {
-            *other->mem.addr() = mozilla::Move(*mem.addr());
+            *other->valuePtr() = mozilla::Move(*valuePtr());
             destroy();
         }
         mozilla::Swap(keyHash, other->keyHash);
     }
 
     T& get() {
         MOZ_ASSERT(isLive());
-        return *mem.addr();
+        return *valuePtr();
     }
 
     NonConstT& getMutable() {
         MOZ_ASSERT(isLive());
-        return *mem.addr();
+        return *valuePtr();
     }
 
     bool isFree() const {
         return keyHash == sFreeKey;
     }
 
     void clearLive() {
         MOZ_ASSERT(isLive());
@@ -906,32 +915,32 @@ class HashTableEntry
         return keyHash & ~sCollisionBit;
     }
 
     template <typename... Args>
     void setLive(HashNumber hn, Args&&... args)
     {
         MOZ_ASSERT(!isLive());
         keyHash = hn;
-        new(mem.addr()) T(mozilla::Forward<Args>(args)...);
+        new (valuePtr()) T(mozilla::Forward<Args>(args)...);
         MOZ_ASSERT(isLive());
     }
 };
 
 template <class T, class HashPolicy, class AllocPolicy>
 class HashTable : private AllocPolicy
 {
     friend class mozilla::ReentrancyGuard;
 
     typedef typename mozilla::RemoveConst<T>::Type NonConstT;
     typedef typename HashPolicy::KeyType Key;
     typedef typename HashPolicy::Lookup Lookup;
 
   public:
-    typedef HashTableEntry<T> Entry;
+    using Entry = HashTableEntry<T>;
 
     // A nullable pointer to a hash table element. A Ptr |p| can be tested
     // either explicitly |if (p.found()) p->...| or using boolean conversion
     // |if (p) p->...|. Ptr objects must not be used after any mutating hash
     // table operations unless |generation()| is tested.
     class Ptr
     {
         friend class HashTable;
@@ -1280,36 +1289,41 @@ class HashTable : private AllocPolicy
         return keyHash & ~sCollisionBit;
     }
 
     enum FailureBehavior { DontReportFailure = false, ReportFailure = true };
 
     static Entry* createTable(AllocPolicy& alloc, uint32_t capacity,
                               FailureBehavior reportFailure = ReportFailure)
     {
-        static_assert(sFreeKey == 0,
-                      "newly-calloc'd tables have to be considered empty");
-        if (reportFailure)
-            return alloc.template pod_calloc<Entry>(capacity);
-
-        return alloc.template maybe_pod_calloc<Entry>(capacity);
+        Entry* table = reportFailure
+                       ? alloc.template pod_malloc<Entry>(capacity)
+                       : alloc.template maybe_pod_malloc<Entry>(capacity);
+        if (table) {
+            for (uint32_t i = 0; i < capacity; i++)
+                new (&table[i]) Entry();
+        }
+        return table;
     }
 
     static Entry* maybeCreateTable(AllocPolicy& alloc, uint32_t capacity)
     {
-        static_assert(sFreeKey == 0,
-                      "newly-calloc'd tables have to be considered empty");
-        return alloc.template maybe_pod_calloc<Entry>(capacity);
+        Entry* table = alloc.template maybe_pod_malloc<Entry>(capacity);
+        if (table) {
+            for (uint32_t i = 0; i < capacity; i++)
+                new (&table[i]) Entry();
+        }
+        return table;
     }
 
     static void destroyTable(AllocPolicy& alloc, Entry* oldTable, uint32_t capacity)
     {
         Entry* end = oldTable + capacity;
         for (Entry* e = oldTable; e < end; ++e)
-            e->destroyIfLive();
+            e->~Entry();
         alloc.free_(oldTable);
     }
 
   public:
     explicit HashTable(AllocPolicy ap)
       : AllocPolicy(ap)
       , gen(0)
       , hashShift(sHashBits)
@@ -1562,18 +1576,19 @@ class HashTable : private AllocPolicy
 
         // Copy only live entries, leaving removed ones behind.
         Entry* end = oldTable + oldCap;
         for (Entry* src = oldTable; src < end; ++src) {
             if (src->isLive()) {
                 HashNumber hn = src->getKeyHash();
                 findFreeEntry(hn).setLive(
                     hn, mozilla::Move(const_cast<typename Entry::NonConstT&>(src->get())));
-                src->destroy();
             }
+
+            src->~Entry();
         }
 
         // All entries have been destroyed, no need to destroyTable.
         this->free_(oldTable);
         return Rehashed;
     }
 
     bool shouldCompressTable()
--- a/js/src/ds/Bitmap.cpp
+++ b/js/src/ds/Bitmap.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ds/Bitmap.h"
 
+#include <algorithm>
+
 using namespace js;
 
 SparseBitmap::~SparseBitmap()
 {
     if (data.initialized()) {
         for (Data::Range r(data.all()); !r.empty(); r.popFront())
             js_delete(r.front().value());
     }
@@ -28,17 +30,17 @@ SparseBitmap::sizeOfExcludingThis(mozill
 SparseBitmap::BitBlock&
 SparseBitmap::createBlock(Data::AddPtr p, size_t blockId)
 {
     MOZ_ASSERT(!p);
     AutoEnterOOMUnsafeRegion oomUnsafe;
     BitBlock* block = js_new<BitBlock>();
     if (!block || !data.add(p, blockId, block))
         oomUnsafe.crash("Bitmap OOM");
-    PodZero(block);
+    std::fill(block->begin(), block->end(), 0);
     return *block;
 }
 
 bool
 SparseBitmap::getBit(size_t bit) const
 {
     size_t word = bit / JS_BITS_PER_WORD;
     size_t blockWord = blockStartWord(word);
--- a/js/src/ds/Bitmap.h
+++ b/js/src/ds/Bitmap.h
@@ -2,17 +2,24 @@
  * 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 ds_Bitmap_h
 #define ds_Bitmap_h
 
+#include "mozilla/Array.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/MemoryChecking.h"
+
 #include <algorithm>
+#include <stddef.h>
+#include <stdint.h>
 
 #include "js/AllocPolicy.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 
 // This file provides two classes for representing bitmaps.
 //
 // DenseBitmap is an array of words of bits, with size linear in the maximum
@@ -21,17 +28,18 @@
 // SparseBitmap provides a reasonably simple, reasonably efficient (in time and
 // space) implementation of a sparse bitmap. The basic representation is a hash
 // table whose entries are fixed length malloc'ed blocks of bits.
 
 namespace js {
 
 class DenseBitmap
 {
-    typedef Vector<uintptr_t, 0, SystemAllocPolicy> Data;
+    using Data = Vector<uintptr_t, 0, SystemAllocPolicy>;
+
     Data data;
 
   public:
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
         return data.sizeOfExcludingThis(mallocSizeOf);
     }
 
     bool ensureSpace(size_t numWords) {
@@ -40,35 +48,38 @@ class DenseBitmap
     }
 
     size_t numWords() const { return data.length(); }
     uintptr_t word(size_t i) const { return data[i]; }
     uintptr_t& word(size_t i) { return data[i]; }
 
     void copyBitsFrom(size_t wordStart, size_t numWords, uintptr_t* source) {
         MOZ_ASSERT(wordStart + numWords <= data.length());
-        mozilla::PodCopy(&data[wordStart], source, numWords);
+        // Use std::copy and not std::copy_n because the former requires no
+        // overlap and so provides extra opportunity to optimize.
+        std::copy(source, source + numWords, &data[wordStart]);
     }
 
     void bitwiseOrRangeInto(size_t wordStart, size_t numWords, uintptr_t* target) const {
         for (size_t i = 0; i < numWords; i++)
             target[i] |= data[wordStart + i];
     }
 };
 
 class SparseBitmap
 {
     // The number of words of bits to use for each block mainly affects the
     // memory usage of the bitmap. To minimize overhead, bitmaps which are
     // expected to be fairly dense should have a large block size, and bitmaps
     // which are expected to be very sparse should have a small block size.
     static const size_t WordsInBlock = 4096 / sizeof(uintptr_t);
 
-    typedef mozilla::Array<uintptr_t, WordsInBlock> BitBlock;
-    typedef HashMap<size_t, BitBlock*, DefaultHasher<size_t>, SystemAllocPolicy> Data;
+    using BitBlock = mozilla::Array<uintptr_t, WordsInBlock>;
+    using Data = HashMap<size_t, BitBlock*, DefaultHasher<size_t>, SystemAllocPolicy>;
+
     Data data;
 
     static size_t blockStartWord(size_t word) {
         return word & ~(WordsInBlock - 1);
     }
 
     // Return the number of words in a BitBlock starting at |blockWord| which
     // are in |other|.
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -3,23 +3,23 @@
  * 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 "gc/Statistics.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
-#include "mozilla/PodOperations.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/TimeStamp.h"
 
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <type_traits>
 
 #include "jsutil.h"
 
 #include "gc/GC.h"
 #include "gc/Memory.h"
 #include "util/Text.h"
 #include "vm/Debugger.h"
 #include "vm/HelperThreads.h"
@@ -27,17 +27,16 @@
 #include "vm/Time.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::gcstats;
 
 using mozilla::DebugOnly;
 using mozilla::EnumeratedArray;
-using mozilla::PodZero;
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 
 /*
  * If this fails, then you can either delete this assertion and allow all
  * larger-numbered reasons to pile up in the last telemetry bucket, or switch
  * to GC_REASON_3 and bump the max value.
  */
@@ -706,17 +705,36 @@ Statistics::Statistics(JSRuntime* rt)
     sliceCallback(nullptr),
     nurseryCollectionCallback(nullptr),
     aborted(false),
     enableProfiling_(false),
     sliceCount_(0)
 {
     for (auto& count : counts)
         count = 0;
-    PodZero(&totalTimes_);
+
+#ifdef DEBUG
+    for (const auto& duration : totalTimes_) {
+#if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_UNIX) && !defined(__clang__))
+        // build-linux64-asan/debug and static-analysis-linux64-st-an/debug
+        // currently use an STL that lacks std::is_trivially_constructible.
+        // This #ifdef probably isn't as precise as it could be, but given
+        // |totalTimes_| contains |TimeDuration| defined platform-independently
+        // it's not worth the trouble to nail down a more exact condition.
+        using ElementType = typename mozilla::RemoveReference<decltype(duration)>::Type;
+        static_assert(!std::is_trivially_constructible<ElementType>::value,
+                      "Statistics::Statistics will only initialize "
+                      "totalTimes_'s elements if their default constructor is "
+                      "non-trivial");
+#endif // mess'o'tests
+        MOZ_ASSERT(duration.IsZero(),
+                   "totalTimes_ default-initialization should have "
+                   "default-initialized every element of totalTimes_ to zero");
+    }
+#endif
 
     MOZ_ALWAYS_TRUE(phaseStack.reserve(MAX_PHASE_NESTING));
     MOZ_ALWAYS_TRUE(suspendedPhases.reserve(MAX_SUSPENDED_PHASES));
 
     const char* env = getenv("MOZ_GCTIMER");
     if (env) {
         if (strcmp(env, "none") == 0) {
             fp = nullptr;
@@ -1093,23 +1111,29 @@ Statistics::endSlice()
     // Do this after the slice callback since it uses these values.
     if (last) {
         for (auto& count : counts)
             count = 0;
 
         // Clear the timers at the end of a GC, preserving the data for PhaseKind::MUTATOR.
         auto mutatorStartTime = phaseStartTimes[Phase::MUTATOR];
         auto mutatorTime = phaseTimes[Phase::MUTATOR];
+
         for (mozilla::TimeStamp& t : phaseStartTimes)
             t = TimeStamp();
 #ifdef DEBUG
         for (mozilla::TimeStamp& t : phaseEndTimes)
             t = TimeStamp();
 #endif
-        PodZero(&phaseTimes);
+
+        for (TimeDuration& duration : phaseTimes) {
+            duration = TimeDuration();
+            MOZ_ASSERT(duration.IsZero());
+        }
+
         phaseStartTimes[Phase::MUTATOR] = mutatorStartTime;
         phaseTimes[Phase::MUTATOR] = mutatorTime;
     }
 
     aborted = false;
 }
 
 void
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -1937,24 +1937,16 @@ bool
 BaselineCacheIRCompiler::emitReturnFromIC()
 {
     allocator.discardStack(masm);
     EmitReturnFromIC(masm);
     return true;
 }
 
 bool
-BaselineCacheIRCompiler::emitLoadObject()
-{
-    Register reg = allocator.defineRegister(masm, reader.objOperandId());
-    masm.loadPtr(stubAddress(reader.stubOffset()), reg);
-    return true;
-}
-
-bool
 BaselineCacheIRCompiler::emitLoadStackValue()
 {
     ValueOperand val = allocator.defineValueRegister(masm, reader.valOperandId());
     Address addr = allocator.addressOf(masm, BaselineFrameSlot(reader.uint32Immediate()));
     masm.loadValue(addr, val);
     return true;
 }
 
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -2990,16 +2990,19 @@ void CacheIRCompiler::emitLoadStubFieldC
         masm.movePtr(ImmGCPtr(shapeStubField(val.getOffset())),dest);
         break;
       case StubField::Type::String:
         masm.movePtr(ImmGCPtr(stringStubField(val.getOffset())), dest);
         break;
       case StubField::Type::ObjectGroup:
         masm.movePtr(ImmGCPtr(groupStubField(val.getOffset())), dest);
         break;
+      case StubField::Type::JSObject:
+        masm.movePtr(ImmGCPtr(objectStubField(val.getOffset())), dest);
+        break;
       default:
         MOZ_CRASH("Unhandled stub field constant type");
     }
 }
 
 /*
  * After this is done executing, dest contains the value; either through a constant load
  * or through the load from the stub data.
@@ -3126,9 +3129,18 @@ CacheIRCompiler::emitGuardGroupHasUnanal
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     emitLoadStubField(group, scratch1);
     masm.guardGroupHasUnanalyzedNewScript(scratch1, scratch2, failure->label());
     return true;
+}
+
+bool
+CacheIRCompiler::emitLoadObject()
+{
+    Register reg = allocator.defineRegister(masm, reader.objOperandId());
+    StubFieldOffset obj(reader.stubOffset(), StubField::Type::JSObject);
+    emitLoadStubField(obj, reg);
+    return true;
 }
\ No newline at end of file
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -36,16 +36,17 @@ namespace jit {
     _(GuardMagicValue)                    \
     _(GuardNoUnboxedExpando)              \
     _(GuardAndLoadUnboxedExpando)         \
     _(GuardNoDetachedTypedObjects)        \
     _(GuardNoDenseElements)               \
     _(GuardAndGetIndexFromString)         \
     _(GuardIndexIsNonNegative)            \
     _(GuardTagNotEqual)                   \
+    _(LoadObject)                         \
     _(LoadProto)                          \
     _(LoadEnclosingEnvironment)           \
     _(LoadWrapperTarget)                  \
     _(LoadValueTag)                       \
     _(LoadDOMExpandoValue)                \
     _(LoadDOMExpandoValueIgnoreGeneration)\
     _(LoadUndefinedResult)                \
     _(LoadBooleanResult)                  \
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -9874,17 +9874,17 @@ CodeGenerator::visitIteratorMore(LIterat
     Address cursorEndAddr(outputScratch, offsetof(NativeIterator, props_end));
     masm.loadPtr(cursorAddr, temp);
     masm.branchPtr(Assembler::BelowOrEqual, cursorEndAddr, temp, &iterDone);
 
     // Get next string.
     masm.loadPtr(Address(temp, 0), temp);
 
     // Increase the cursor.
-    masm.addPtr(Imm32(sizeof(JSString*)), cursorAddr);
+    masm.addPtr(Imm32(sizeof(GCPtrFlatString)), cursorAddr);
 
     masm.tagValue(JSVAL_TYPE_STRING, temp, output);
     masm.jump(ool->rejoin());
 
     masm.bind(&iterDone);
     masm.moveValue(MagicValue(JS_NO_ITER_VALUE), output);
 
     masm.bind(ool->rejoin());
@@ -9918,18 +9918,19 @@ CodeGenerator::visitIteratorEnd(LIterato
     OutOfLineCode* ool = oolCallVM(CloseIteratorFromIonInfo, lir, ArgList(obj), StoreNothing());
 
     LoadNativeIterator(masm, obj, temp1, ool->entry());
 
     // Clear active bit.
     masm.and32(Imm32(~JSITER_ACTIVE), Address(temp1, offsetof(NativeIterator, flags)));
 
     // Reset property cursor.
-    masm.loadPtr(Address(temp1, offsetof(NativeIterator, props_array)), temp2);
-    masm.storePtr(temp2, Address(temp1, offsetof(NativeIterator, props_cursor)));
+    Address propCursor(temp1, offsetof(NativeIterator, props_cursor));
+    masm.computeEffectiveAddress(Address(temp1, sizeof(NativeIterator)), temp2);
+    masm.storePtr(temp2, propCursor);
 
     // Unlink from the iterator list.
     const Register next = temp2;
     const Register prev = temp3;
     masm.loadPtr(Address(temp1, NativeIterator::offsetOfNext()), next);
     masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), prev);
     masm.storePtr(prev, Address(next, NativeIterator::offsetOfPrev()));
     masm.storePtr(next, Address(prev, NativeIterator::offsetOfNext()));
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -2268,25 +2268,16 @@ IonCacheIRCompiler::emitReturnFromIC()
 
     RepatchLabel rejoin;
     rejoinOffset_ = masm.jumpWithPatch(&rejoin);
     masm.bind(&rejoin);
     return true;
 }
 
 bool
-IonCacheIRCompiler::emitLoadObject()
-{
-    Register reg = allocator.defineRegister(masm, reader.objOperandId());
-    JSObject* obj = objectStubField(reader.stubOffset());
-    masm.movePtr(ImmGCPtr(obj), reg);
-    return true;
-}
-
-bool
 IonCacheIRCompiler::emitLoadStackValue()
 {
     MOZ_ASSERT_UNREACHABLE("emitLoadStackValue not supported for IonCaches.");
     return false;
 }
 
 bool
 IonCacheIRCompiler::emitGuardAndGetIterator()
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -906,17 +906,17 @@ class SpecializedRegSet<Accessors, Regis
     void takeUnchecked(AnyRegister reg) {
         if (reg.isFloat())
             takeUnchecked(reg.fpu());
         else
             takeUnchecked(reg.gpr());
     }
 
     void take(Register reg) {
-        MOZ_ASSERT(has(reg));
+        MOZ_ASSERT(this->has(reg));
         takeUnchecked(reg);
     }
     void take(FloatRegister reg) {
         MOZ_ASSERT(has(reg));
         takeUnchecked(reg);
     }
     void take(AnyRegister reg) {
         if (reg.isFloat())
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5889,21 +5889,21 @@ namespace JS {
  * This callback represents a request by the JS engine to open for reading the
  * existing cache entry for the given global and char range that may contain a
  * module. If a cache entry exists, the callback shall return 'true' and return
  * the size, base address and an opaque file handle as outparams. If the
  * callback returns 'true', the JS engine guarantees a call to
  * CloseAsmJSCacheEntryForReadOp, passing the same base address, size and
  * handle.
  */
-typedef bool
-(* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const char16_t* begin, const char16_t* limit,
-                                 size_t* size, const uint8_t** memory, intptr_t* handle);
-typedef void
-(* CloseAsmJSCacheEntryForReadOp)(size_t size, const uint8_t* memory, intptr_t handle);
+using OpenAsmJSCacheEntryForReadOp =
+    bool (*)(HandleObject global, const char16_t* begin, const char16_t* limit, size_t* size,
+             const uint8_t** memory, intptr_t* handle);
+using CloseAsmJSCacheEntryForReadOp =
+    void (*)(size_t size, const uint8_t* memory, intptr_t handle);
 
 /** The list of reasons why an asm.js module may not be stored in the cache. */
 enum AsmJSCacheResult
 {
     AsmJSCache_Success,
     AsmJSCache_MIN = AsmJSCache_Success,
     AsmJSCache_ModuleTooSmall,
     AsmJSCache_SynchronousScript,
@@ -5921,29 +5921,28 @@ enum AsmJSCacheResult
  * This callback represents a request by the JS engine to open for writing a
  * cache entry of the given size for the given global and char range containing
  * the just-compiled module. If cache entry space is available, the callback
  * shall return 'true' and return the base address and an opaque file handle as
  * outparams. If the callback returns 'true', the JS engine guarantees a call
  * to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and
  * handle.
  */
-typedef AsmJSCacheResult
-(* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, const char16_t* begin,
-                                  const char16_t* end, size_t size,
-                                  uint8_t** memory, intptr_t* handle);
-typedef void
-(* CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, intptr_t handle);
+using OpenAsmJSCacheEntryForWriteOp =
+    AsmJSCacheResult (*)(HandleObject global, const char16_t* begin, const char16_t* end,
+                         size_t size, uint8_t** memory, intptr_t* handle);
+using CloseAsmJSCacheEntryForWriteOp =
+    void (*)(size_t size, uint8_t* memory, intptr_t handle);
 
 struct AsmJSCacheOps
 {
-    OpenAsmJSCacheEntryForReadOp openEntryForRead;
-    CloseAsmJSCacheEntryForReadOp closeEntryForRead;
-    OpenAsmJSCacheEntryForWriteOp openEntryForWrite;
-    CloseAsmJSCacheEntryForWriteOp closeEntryForWrite;
+    OpenAsmJSCacheEntryForReadOp openEntryForRead = nullptr;
+    CloseAsmJSCacheEntryForReadOp closeEntryForRead = nullptr;
+    OpenAsmJSCacheEntryForWriteOp openEntryForWrite = nullptr;
+    CloseAsmJSCacheEntryForWriteOp closeEntryForWrite = nullptr;
 };
 
 extern JS_PUBLIC_API(void)
 SetAsmJSCacheOps(JSContext* cx, const AsmJSCacheOps* callbacks);
 
 /**
  * Return the buildId (represented as a sequence of characters) associated with
  * the currently-executing build. If the JS engine is embedded such that a
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -502,32 +502,29 @@ ArrayBufferObjectMaybeShared& AsArrayBuf
 ArrayBufferObjectMaybeShared& AsArrayBufferMaybeShared(JSObject* obj);
 
 extern uint32_t JS_FASTCALL
 ClampDoubleToUint8(const double x);
 
 struct uint8_clamped {
     uint8_t val;
 
-    uint8_clamped() { }
-    uint8_clamped(const uint8_clamped& other) : val(other.val) { }
+    uint8_clamped() = default;
+    uint8_clamped(const uint8_clamped& other) = default;
 
     // invoke our assignment helpers for constructor conversion
     explicit uint8_clamped(uint8_t x)    { *this = x; }
     explicit uint8_clamped(uint16_t x)   { *this = x; }
     explicit uint8_clamped(uint32_t x)   { *this = x; }
     explicit uint8_clamped(int8_t x)     { *this = x; }
     explicit uint8_clamped(int16_t x)    { *this = x; }
     explicit uint8_clamped(int32_t x)    { *this = x; }
     explicit uint8_clamped(double x)     { *this = x; }
 
-    uint8_clamped& operator=(const uint8_clamped& x) {
-        val = x.val;
-        return *this;
-    }
+    uint8_clamped& operator=(const uint8_clamped& x) = default;
 
     uint8_clamped& operator=(uint8_t x) {
         val = x;
         return *this;
     }
 
     uint8_clamped& operator=(uint16_t x) {
         val = (x > 255) ? 255 : uint8_t(x);
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -9,16 +9,18 @@
 #include "vm/Iteration.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Unused.h"
 
+#include <new>
+
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "builtin/Array.h"
 #include "ds/Sort.h"
 #include "gc/FreeOp.h"
 #include "gc/Marking.h"
 #include "js/Proxy.h"
@@ -41,31 +43,31 @@
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::DebugOnly;
 using mozilla::Maybe;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
-using mozilla::PodZero;
 
 typedef Rooted<PropertyIteratorObject*> RootedPropertyIteratorObject;
 
 static const gc::AllocKind ITERATOR_FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
 
 void
 NativeIterator::trace(JSTracer* trc)
 {
     for (GCPtrFlatString* str = begin(); str < end(); str++)
         TraceNullableEdge(trc, str, "prop");
     TraceNullableEdge(trc, &obj, "obj");
 
+    HeapReceiverGuard* guards = guardArray();
     for (size_t i = 0; i < guard_length; i++)
-        guard_array[i].trace(trc);
+        guards[i].trace(trc);
 
     // The SuppressDeletedPropertyHelper loop can GC, so make sure that if the
     // GC removes any elements from the list, it won't remove this one.
     if (iterObj_)
         TraceManuallyBarrieredEdge(trc, &iterObj_, "iterObj");
 }
 
 typedef HashSet<jsid, DefaultHasher<jsid>> IdSet;
@@ -528,17 +530,27 @@ Snapshot(JSContext* cx, HandleObject pob
 JS_FRIEND_API(bool)
 js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector* props)
 {
     return Snapshot(cx, obj,
                     flags & (JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY),
                     props);
 }
 
-static inline PropertyIteratorObject*
+static inline void
+RegisterEnumerator(JSContext* cx, NativeIterator* ni)
+{
+    /* Register non-escaping native enumerators (for-in) with the current context. */
+    ni->link(cx->compartment()->enumerators);
+
+    MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
+    ni->flags |= JSITER_ACTIVE;
+}
+
+static PropertyIteratorObject*
 NewPropertyIteratorObject(JSContext* cx)
 {
     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_,
                                                              TaggedProto(nullptr)));
     if (!group)
         return nullptr;
 
     const Class* clasp = &PropertyIteratorObject::class_;
@@ -557,178 +569,197 @@ NewPropertyIteratorObject(JSContext* cx)
     // CodeGenerator::visitIteratorStartO assumes the iterator object is not
     // inside the nursery when deciding whether a barrier is necessary.
     MOZ_ASSERT(!js::gc::IsInsideNursery(res));
 
     MOZ_ASSERT(res->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
     return res;
 }
 
-NativeIterator*
-NativeIterator::allocateIterator(JSContext* cx, uint32_t numGuards, uint32_t plength)
+static PropertyIteratorObject*
+CreatePropertyIterator(JSContext* cx, Handle<JSObject*> objBeingIterated,
+                       const AutoIdVector& props, uint32_t numGuards, uint32_t guardKey)
 {
-    JS_STATIC_ASSERT(sizeof(ReceiverGuard) == 2 * sizeof(void*));
+    Rooted<PropertyIteratorObject*> propIter(cx, NewPropertyIteratorObject(cx));
+    if (!propIter)
+        return nullptr;
 
-    size_t extraLength = plength + numGuards * 2;
-    NativeIterator* ni = cx->zone()->pod_malloc_with_extra<NativeIterator, void*>(extraLength);
-    if (!ni) {
+    static_assert(sizeof(ReceiverGuard) == 2 * sizeof(GCPtrFlatString),
+                  "NativeIterators are allocated in space for 1) themselves, "
+                  "2) the properties a NativeIterator iterates (as "
+                  "GCPtrFlatStrings), and 3) |numGuards| HeapReceiverGuard "
+                  "objects; the additional-length calculation below assumes "
+                  "this size-relationship when determining the extra space to "
+                  "allocate");
+
+    size_t extraCount = props.length() + numGuards * 2;
+    void* mem =
+        cx->zone()->pod_malloc_with_extra<NativeIterator, GCPtrFlatString>(extraCount);
+    if (!mem) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    void** extra = reinterpret_cast<void**>(ni + 1);
-    PodZero(ni);
-    PodZero(extra, extraLength);
-    ni->props_array = ni->props_cursor = reinterpret_cast<GCPtrFlatString*>(extra);
-    ni->props_end = ni->props_array + plength;
-    return ni;
+    // This also registers |ni| with |propIter|.
+    bool hadError = false;
+    NativeIterator* ni =
+        new (mem) NativeIterator(cx, propIter, objBeingIterated, props, numGuards, guardKey,
+                                 &hadError);
+    if (hadError)
+        return nullptr;
+
+    RegisterEnumerator(cx, ni);
+    return propIter;
+}
+
+/**
+ * Initialize a sentinel NativeIterator whose purpose is only to act as the
+ * start/end of the circular linked list of NativeIterators in
+ * JSCompartment::enumerators.
+ */
+NativeIterator::NativeIterator()
+{
+    // Do our best to enforce that nothing in |this| except the two fields set
+    // below is ever observed.
+    JS_POISON(static_cast<void*>(this), 0xCC, sizeof(*this), MemCheckKind::MakeUndefined);
+
+    // These are the only two fields in sentinel NativeIterators that are
+    // examined, in JSCompartment::sweepNativeIterators.  Everything else is
+    // only examined *if* it's a NativeIterator being traced by a
+    // PropertyIteratorObject that owns it, and nothing owns this iterator.
+    prev_ = next_ = this;
 }
 
 NativeIterator*
 NativeIterator::allocateSentinel(JSContext* maybecx)
 {
-    NativeIterator* ni = js_pod_malloc<NativeIterator>();
+    NativeIterator* ni = js_new<NativeIterator>();
     if (!ni) {
         if (maybecx)
             ReportOutOfMemory(maybecx);
-        return nullptr;
     }
 
-    PodZero(ni);
-
-    ni->next_ = ni;
-    ni->prev_ = ni;
     return ni;
 }
 
-inline void
-NativeIterator::init(JSObject* obj, JSObject* iterObj, uint32_t numGuards, uint32_t key)
+/**
+ * Initialize a fresh NativeIterator.
+ *
+ * This definition is a bit tricky: some parts of initializing are fallible, so
+ * as we initialize, we must carefully keep this in GC-safe state (see
+ * NativeIterator::trace).
+ */
+NativeIterator::NativeIterator(JSContext* cx, Handle<PropertyIteratorObject*> propIter,
+                               Handle<JSObject*> objBeingIterated, const AutoIdVector& props,
+                               uint32_t numGuards, uint32_t guardKey, bool* hadError)
+  : obj(objBeingIterated),
+    iterObj_(propIter),
+    // NativeIterator initially acts as if it contains no properties.
+    props_cursor(begin()),
+    props_end(props_cursor),
+    // ...and no HeapReceiverGuards.
+    guard_length(0),
+    guard_key(guardKey),
+    flags(0)
 {
-    this->obj.init(obj);
-    this->iterObj_ = iterObj;
-    this->flags = 0;
-    this->guard_array = (HeapReceiverGuard*) this->props_end;
-    this->guard_length = numGuards;
-    this->guard_key = key;
-}
+    MOZ_ASSERT(!*hadError);
 
-bool
-NativeIterator::initProperties(JSContext* cx, Handle<PropertyIteratorObject*> obj,
-                               const AutoIdVector& props)
-{
-    // The obj parameter is just so that we can ensure that this object will get
-    // traced if we GC.
-    MOZ_ASSERT(this == obj->getNativeIterator());
+    // NOTE: This must be done first thing: PropertyIteratorObject::finalize
+    //       can only free |this| (and not leak it) if this has happened.
+    propIter->setNativeIterator(this);
+
+    for (size_t i = 0, len = props.length(); i < len; i++) {
+        JSFlatString* str = IdToString(cx, props[i]);
+        if (!str) {
+            *hadError = true;
+            return;
+        }
 
-    size_t plength = props.length();
-    MOZ_ASSERT(plength == size_t(end() - begin()));
+        // Placement-new the next property string at the end of the currently
+        // computed property strings.
+        GCPtrFlatString* loc = props_end;
 
-    for (size_t i = 0; i < plength; i++) {
-        JSFlatString* str = IdToString(cx, props[i]);
-        if (!str)
-            return false;
-        props_array[i].init(str);
+        // Increase the overall property string count before initializing the
+        // property string, so this construction isn't on a location not known
+        // to the GC yet.
+        props_end++;
+
+        new (loc) GCPtrFlatString(str);
     }
 
-    return true;
-}
-
-static inline void
-RegisterEnumerator(JSContext* cx, NativeIterator* ni)
-{
-    /* Register non-escaping native enumerators (for-in) with the current context. */
-    ni->link(cx->compartment()->enumerators);
-
-    MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
-    ni->flags |= JSITER_ACTIVE;
-}
-
-static inline PropertyIteratorObject*
-VectorToKeyIterator(JSContext* cx, HandleObject obj, AutoIdVector& keys, uint32_t numGuards)
-{
-    if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj))
-        return nullptr;
-    MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
-
-    Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx));
-    if (!iterobj)
-        return nullptr;
-
-    NativeIterator* ni = NativeIterator::allocateIterator(cx, numGuards, keys.length());
-    if (!ni)
-        return nullptr;
-
-    iterobj->setNativeIterator(ni);
-    ni->init(obj, iterobj, numGuards, 0);
-    if (!ni->initProperties(cx, iterobj, keys))
-        return nullptr;
-
-    if (numGuards) {
-        // Fill in the guard array from scratch. Also recompute the guard key
-        // as we might have reshaped the object (see for instance the
-        // setIteratedSingleton call above) or GC might have moved shapes and
-        // groups in memory.
-        JSObject* pobj = obj;
-        size_t ind = 0;
+    if (numGuards > 0) {
+        // Construct guards into the guard array.  Also recompute the guard key,
+        // which incorporates Shape* and ObjectGroup* addresses that could have
+        // changed during a GC triggered in (among other places) |IdToString|
+        //. above.
+        JSObject* pobj = objBeingIterated;
         uint32_t key = 0;
+        HeapReceiverGuard* guards = guardArray();
         do {
             ReceiverGuard guard(pobj);
-            ni->guard_array[ind++].init(guard);
+
+            // Placement-new the next HeapReceiverGuard at the end of the
+            // currently initialized HeapReceiverGuards.
+            uint32_t index = guard_length;
+
+            // Increase the overall guard-count before initializing the
+            // HeapReceiverGuard, so this construction isn't on a location not
+            // known to the GC.
+            guard_length++;
+
+            new (&guards[index]) HeapReceiverGuard(guard);
+
             key = mozilla::AddToHash(key, guard.hash());
 
             // The one caller of this method that passes |numGuards > 0|, does
             // so only if the entire chain consists of cacheable objects (that
             // necessarily have static prototypes).
             pobj = pobj->staticPrototype();
         } while (pobj);
-        ni->guard_key = key;
-        MOZ_ASSERT(ind == numGuards);
+
+        guard_key = key;
+        MOZ_ASSERT(guard_length == numGuards);
     }
 
-    RegisterEnumerator(cx, ni);
-    return iterobj;
+    MOZ_ASSERT(!*hadError);
+}
+
+static inline PropertyIteratorObject*
+VectorToKeyIterator(JSContext* cx, HandleObject obj, AutoIdVector& props, uint32_t numGuards)
+{
+    if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj))
+        return nullptr;
+    MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
+
+    return CreatePropertyIterator(cx, obj, props, numGuards, 0);
 }
 
 
 JSObject*
 js::EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, AutoIdVector& props)
 {
     return VectorToKeyIterator(cx, obj, props, 0);
 }
 
 // Mainly used for .. in over null/undefined
 JSObject*
 js::NewEmptyPropertyIterator(JSContext* cx)
 {
-    Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx));
-    if (!iterobj)
-        return nullptr;
-
-    AutoIdVector keys(cx); // Empty
-    NativeIterator* ni = NativeIterator::allocateIterator(cx, 0, keys.length());
-    if (!ni)
-        return nullptr;
-
-    iterobj->setNativeIterator(ni);
-    ni->init(nullptr, iterobj, 0, 0);
-    if (!ni->initProperties(cx, iterobj, keys))
-        return nullptr;
-
-    RegisterEnumerator(cx, ni);
-    return iterobj;
+    AutoIdVector props(cx); // Empty
+    return CreatePropertyIterator(cx, nullptr, props, 0, 0);
 }
 
 /* static */ bool
 IteratorHashPolicy::match(PropertyIteratorObject* obj, const Lookup& lookup)
 {
     NativeIterator* ni = obj->getNativeIterator();
     if (ni->guard_key != lookup.key || ni->guard_length != lookup.numGuards)
         return false;
 
-    return PodEqual(reinterpret_cast<ReceiverGuard*>(ni->guard_array), lookup.guards,
+    return PodEqual(reinterpret_cast<ReceiverGuard*>(ni->guardArray()), lookup.guards,
                     ni->guard_length);
 }
 
 static inline void
 UpdateNativeIterator(NativeIterator* ni, JSObject* obj)
 {
     // Update the object for which the native iterator is associated, so
     // SuppressDeletedPropertyHelper will recognize the iterator as a match.
@@ -818,18 +849,19 @@ CanStoreInIteratorCache(JSObject* obj)
 static MOZ_MUST_USE bool
 StoreInIteratorCache(JSContext* cx, JSObject* obj, PropertyIteratorObject* iterobj)
 {
     MOZ_ASSERT(CanStoreInIteratorCache(obj));
 
     NativeIterator* ni = iterobj->getNativeIterator();
     MOZ_ASSERT(ni->guard_length > 0);
 
-    IteratorHashPolicy::Lookup lookup(reinterpret_cast<ReceiverGuard*>(ni->guard_array),
-                                      ni->guard_length, ni->guard_key);
+    IteratorHashPolicy::Lookup lookup(reinterpret_cast<ReceiverGuard*>(ni->guardArray()),
+                                      ni->guard_length,
+                                      ni->guard_key);
 
     JSCompartment::IteratorCache& cache = cx->compartment()->iteratorCache;
     bool ok;
     auto p = cache.lookupForAdd(lookup);
     if (MOZ_LIKELY(!p)) {
         ok = cache.add(p, iterobj);
     } else {
         // If we weren't able to use an existing cached iterator, just
@@ -1131,17 +1163,17 @@ js::CloseIterator(JSObject* obj)
 
         MOZ_ASSERT(ni->flags & JSITER_ACTIVE);
         ni->flags &= ~JSITER_ACTIVE;
 
         /*
          * Reset the enumerator; it may still be in the cached iterators
          * for this thread, and can be reused.
          */
-        ni->props_cursor = ni->props_array;
+        ni->props_cursor = ni->begin();
     }
 }
 
 bool
 js::IteratorCloseForException(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(cx->isExceptionPending());
 
--- a/js/src/vm/Iteration.h
+++ b/js/src/vm/Iteration.h
@@ -26,40 +26,87 @@
 #define JSITER_UNREUSABLE   0x2000
 
 namespace js {
 
 class PropertyIteratorObject;
 
 struct NativeIterator
 {
-    GCPtrObject obj;    // Object being iterated.
-    JSObject* iterObj_; // Internal iterator object.
-    GCPtrFlatString* props_array;
-    GCPtrFlatString* props_cursor;
-    GCPtrFlatString* props_end;
-    HeapReceiverGuard* guard_array;
-    uint32_t guard_length;
-    uint32_t guard_key;
-    uint32_t flags;
+    // Object being iterated.
+    GCPtrObject obj = {};
+
+    // Internal iterator object.
+    JSObject* iterObj_ = nullptr;
+
+    // The next property, pointing into an array of strings directly after this
+    // NativeIterator as part of the overall allocation containing |*this|.
+    GCPtrFlatString* props_cursor; // initialized by constructor
+
+    // The limit/end of properties to iterate.  (This is also, after casting,
+    // the start of an array of HeapReceiverGuards included in the overall
+    // allocation that stores |*this| and the iterated strings.)
+    GCPtrFlatString* props_end; // initialized by constructor
+
+    uint32_t guard_length = 0;
+    uint32_t guard_key = 0;
+    uint32_t flags = 0;
 
   private:
     /* While in compartment->enumerators, these form a doubly linked list. */
-    NativeIterator* next_;
-    NativeIterator* prev_;
+    NativeIterator* next_ = nullptr;
+    NativeIterator* prev_ = nullptr;
+
+    // No further fields appear after here *in NativeIterator*, but this class
+    // is always allocated with space tacked on immediately after |this| to
+    // store iterated property names up to |props_end| and |guard_length|
+    // HeapReceiverGuards after that.
 
   public:
-    inline GCPtrFlatString* begin() const {
-        return props_array;
+    /**
+     * Initialize a NativeIterator properly allocated for |props.length()|
+     * properties and |numGuards| guards.
+     *
+     * Despite being a constructor, THIS FUNCTION CAN REPORT ERRORS.  Users
+     * MUST set |*hadError = false| on entry and consider |*hadError| on return
+     * to mean this function failed.
+     */
+    NativeIterator(JSContext* cx, Handle<PropertyIteratorObject*> propIter,
+                   Handle<JSObject*> objBeingIterated, const AutoIdVector& props,
+                   uint32_t numGuards, uint32_t guardKey, bool* hadError);
+
+    /** Initialize a |JSCompartment::enumerators| sentinel. */
+    NativeIterator();
+
+    GCPtrFlatString* begin() const {
+        static_assert(alignof(NativeIterator) >= alignof(GCPtrFlatString),
+                      "GCPtrFlatStrings for properties must be able to appear "
+                      "directly after NativeIterator, with no padding space "
+                      "required for correct alignment");
+
+        // Note that JIT code inlines this computation to reset |props_cursor|
+        // when an iterator ends: see |CodeGenerator::visitIteratorEnd|.
+        const NativeIterator* immediatelyAfter = this + 1;
+        auto* afterNonConst = const_cast<NativeIterator*>(immediatelyAfter);
+        return reinterpret_cast<GCPtrFlatString*>(afterNonConst);
     }
 
-    inline GCPtrFlatString* end() const {
+    GCPtrFlatString* end() const {
         return props_end;
     }
 
+    HeapReceiverGuard* guardArray() const {
+        static_assert(alignof(ReceiverGuard) == alignof(GCPtrFlatString),
+                      "the end of all properties must be exactly aligned "
+                      "adequate to begin storing ReceiverGuards, else the "
+                      "full tacked-on memory won't be enough to store all "
+                      "properties/guards");
+        return reinterpret_cast<HeapReceiverGuard*>(props_end);
+    }
+
     size_t numKeys() const {
         return end() - begin();
     }
 
     JSObject* iterObj() const {
         return iterObj_;
     }
     GCPtrFlatString* current() const {
@@ -93,26 +140,18 @@ struct NativeIterator
     void unlink() {
         next_->prev_ = prev_;
         prev_->next_ = next_;
         next_ = nullptr;
         prev_ = nullptr;
     }
 
     static NativeIterator* allocateSentinel(JSContext* maybecx);
-    static NativeIterator* allocateIterator(JSContext* cx, uint32_t slength, uint32_t plength);
-    void init(JSObject* obj, JSObject* iterObj, uint32_t slength, uint32_t key);
-    bool initProperties(JSContext* cx, Handle<PropertyIteratorObject*> obj,
-                        const js::AutoIdVector& props);
 
     void trace(JSTracer* trc);
-
-    static void destroy(NativeIterator* iter) {
-        js_free(iter);
-    }
 };
 
 class PropertyIteratorObject : public NativeObject
 {
     static const ClassOps classOps_;
 
   public:
     static const Class class_;
--- a/js/src/vm/JSScript-inl.h
+++ b/js/src/vm/JSScript-inl.h
@@ -199,12 +199,12 @@ JSScript::ensureHasAnalyzedArgsUsage(JSC
     if (analyzedArgsUsage())
         return true;
     return js::jit::AnalyzeArgumentsUsage(cx, this);
 }
 
 inline bool
 JSScript::isDebuggee() const
 {
-    return realm_->debuggerObservesAllExecution() || hasDebugScript_;
+    return realm_->debuggerObservesAllExecution() || bitFields_.hasDebugScript_;
 }
 
 #endif /* vm_JSScript_inl_h */
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Vector.h"
 
 #include <algorithm>
+#include <new>
 #include <string.h>
 
 #include "jsapi.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
@@ -63,17 +64,16 @@
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 using mozilla::Maybe;
 using mozilla::PodCopy;
-using mozilla::PodZero;
 
 
 // Check that JSScript::data hasn't experienced obvious memory corruption.
 // This is a diagnositic for Bug 1367896.
 static void
 CheckScriptDataIntegrity(JSScript* script)
 {
     ScopeArray* sa = script->scopes();
@@ -553,49 +553,49 @@ js::XDRScript(XDRState<mode>* xdr, Handl
 
         MOZ_ASSERT(!script->mainOffset());
         script->mainOffset_ = prologueLength;
         script->funLength_ = funLength;
 
         scriptp.set(script);
 
         if (scriptBits & (1 << Strict))
-            script->strict_ = true;
+            script->bitFields_.strict_ = true;
         if (scriptBits & (1 << ExplicitUseStrict))
-            script->explicitUseStrict_ = true;
+            script->bitFields_.explicitUseStrict_ = true;
         if (scriptBits & (1 << ContainsDynamicNameAccess))
-            script->bindingsAccessedDynamically_ = true;
+            script->bitFields_.bindingsAccessedDynamically_ = true;
         if (scriptBits & (1 << FunHasExtensibleScope))
-            script->funHasExtensibleScope_ = true;
+            script->bitFields_.funHasExtensibleScope_ = true;
         if (scriptBits & (1 << FunHasAnyAliasedFormal))
-            script->funHasAnyAliasedFormal_ = true;
+            script->bitFields_.funHasAnyAliasedFormal_ = true;
         if (scriptBits & (1 << ArgumentsHasVarBinding))
             script->setArgumentsHasVarBinding();
         if (scriptBits & (1 << NeedsArgsObj))
             script->setNeedsArgsObj(true);
         if (scriptBits & (1 << HasMappedArgsObj))
-            script->hasMappedArgsObj_ = true;
+            script->bitFields_.hasMappedArgsObj_ = true;
         if (scriptBits & (1 << FunctionHasThisBinding))
-            script->functionHasThisBinding_ = true;
+            script->bitFields_.functionHasThisBinding_ = true;
         if (scriptBits & (1 << FunctionHasExtraBodyVarScope))
-            script->functionHasExtraBodyVarScope_ = true;
+            script->bitFields_.functionHasExtraBodyVarScope_ = true;
         if (scriptBits & (1 << HasSingleton))
-            script->hasSingletons_ = true;
+            script->bitFields_.hasSingletons_ = true;
         if (scriptBits & (1 << TreatAsRunOnce))
-            script->treatAsRunOnce_ = true;
+            script->bitFields_.treatAsRunOnce_ = true;
         if (scriptBits & (1 << HasNonSyntacticScope))
-            script->hasNonSyntacticScope_ = true;
+            script->bitFields_.hasNonSyntacticScope_ = true;
         if (scriptBits & (1 << HasInnerFunctions))
-            script->hasInnerFunctions_ = true;
+            script->bitFields_.hasInnerFunctions_ = true;
         if (scriptBits & (1 << NeedsHomeObject))
-            script->needsHomeObject_ = true;
+            script->bitFields_.needsHomeObject_ = true;
         if (scriptBits & (1 << IsDerivedClassConstructor))
-            script->isDerivedClassConstructor_ = true;
+            script->bitFields_.isDerivedClassConstructor_ = true;
         if (scriptBits & (1 << IsDefaultClassConstructor))
-            script->isDefaultClassConstructor_ = true;
+            script->bitFields_.isDefaultClassConstructor_ = true;
         if (scriptBits & (1 << IsGenerator))
             script->setGeneratorKind(GeneratorKind::Generator);
         if (scriptBits & (1 << IsAsync))
             script->setAsyncKind(FunctionAsyncKind::AsyncFunction);
         if (scriptBits & (1 << HasRest))
             script->setHasRest();
     }
 
@@ -1081,17 +1081,17 @@ JSScript::initScriptCounts(JSContext* cx
 
     // Register the current ScriptCounts in the compartment's map.
     if (!map->putNew(this, sc)) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     // safe to set this;  we can't fail after this point.
-    hasScriptCounts_ = true;
+    bitFields_.hasScriptCounts_ = true;
     guardScriptCounts.release();
 
     // Enable interrupts in any interpreter frames running on this script. This
     // is used to let the interpreter increment the PCCounts, if present.
     for (ActivationIterator iter(cx); !iter.done(); ++iter) {
         if (iter->isInterpreter())
             iter->asInterpreter()->enableInterruptsIfRunning(this);
     }
@@ -1293,27 +1293,27 @@ JSScript::getIonCounts()
 
 void
 JSScript::takeOverScriptCountsMapEntry(ScriptCounts* entryValue)
 {
 #ifdef DEBUG
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
     MOZ_ASSERT(entryValue == p->value());
 #endif
-    hasScriptCounts_ = false;
+    bitFields_.hasScriptCounts_ = false;
 }
 
 void
 JSScript::releaseScriptCounts(ScriptCounts* counts)
 {
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
     *counts = Move(*p->value());
     js_delete(p->value());
     compartment()->scriptCountsMap->remove(p);
-    hasScriptCounts_ = false;
+    bitFields_.hasScriptCounts_ = false;
 }
 
 void
 JSScript::destroyScriptCounts()
 {
     if (hasScriptCounts()) {
         ScriptCounts scriptCounts;
         releaseScriptCounts(&scriptCounts);
@@ -2621,60 +2621,86 @@ ScriptDataSize(uint32_t nscopes, uint32_
     if (nscopenotes != 0)
         size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
     if (nyieldoffsets != 0)
         size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
 
      return size;
 }
 
-/* static */ JSScript*
-JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
-                 HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
-                 uint32_t toStringStart, uint32_t toStringEnd)
+JSScript::JSScript(JS::Realm* realm, uint8_t* stubEntry, const ReadOnlyCompileOptions& options,
+                   HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
+                   uint32_t toStringStart, uint32_t toStringEnd)
+  :
+#ifndef JS_CODEGEN_NONE
+    jitCodeRaw_(stubEntry),
+    jitCodeSkipArgCheck_(stubEntry),
+#endif
+    realm_(realm),
+    sourceStart_(bufStart),
+    sourceEnd_(bufEnd),
+    toStringStart_(toStringStart),
+    toStringEnd_(toStringEnd),
+#ifdef MOZ_VTUNE
+    vtuneMethodId_(vtune::GenerateUniqueMethodID()),
+#endif
+    bitFields_{} // zeroes everything -- some fields custom-assigned below
 {
     // bufStart and bufEnd specify the range of characters parsed by the
     // Parser to produce this script. toStringStart and toStringEnd specify
     // the range of characters to be returned for Function.prototype.toString.
     MOZ_ASSERT(bufStart <= bufEnd);
     MOZ_ASSERT(toStringStart <= toStringEnd);
     MOZ_ASSERT(toStringStart <= bufStart);
     MOZ_ASSERT(toStringEnd >= bufEnd);
 
-    RootedScript script(cx, Allocate<JSScript>(cx));
+    bitFields_.noScriptRval_ = options.noScriptRval;
+    bitFields_.selfHosted_ = options.selfHostingMode;
+    bitFields_.treatAsRunOnce_ = options.isRunOnce;
+    bitFields_.hideScriptFromDebugger_ = options.hideScriptFromDebugger;
+
+    setSourceObject(sourceObject);
+}
+
+/* static */ JSScript*
+JSScript::createInitialized(JSContext* cx, const ReadOnlyCompileOptions& options,
+                            HandleObject sourceObject,
+                            uint32_t bufStart, uint32_t bufEnd,
+                            uint32_t toStringStart, uint32_t toStringEnd)
+{
+    void* script = Allocate<JSScript>(cx);
     if (!script)
         return nullptr;
 
-    PodZero(script.get());
-
-    script->realm_ = cx->realm();
-
+    uint8_t* stubEntry =
 #ifndef JS_CODEGEN_NONE
-    uint8_t* stubEntry = cx->runtime()->jitRuntime()->interpreterStub().value;
-    script->jitCodeRaw_ = stubEntry;
-    script->jitCodeSkipArgCheck_ = stubEntry;
+        cx->runtime()->jitRuntime()->interpreterStub().value
+#else
+        nullptr
 #endif
-
-    script->selfHosted_ = options.selfHostingMode;
-    script->noScriptRval_ = options.noScriptRval;
-    script->treatAsRunOnce_ = options.isRunOnce;
-
-    script->setSourceObject(sourceObject);
-    if (cx->runtime()->lcovOutput().isEnabled() && !script->initScriptName(cx))
+        ;
+
+    return new (script) JSScript(cx->realm(), stubEntry, options, sourceObject,
+                                 bufStart, bufEnd, toStringStart, toStringEnd);
+}
+
+/* static */ JSScript*
+JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
+                 HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
+                 uint32_t toStringStart, uint32_t toStringEnd)
+{
+    RootedScript script(cx, createInitialized(cx, options, sourceObject, bufStart, bufEnd,
+                                              toStringStart, toStringEnd));
+    if (!script)
         return nullptr;
-    script->sourceStart_ = bufStart;
-    script->sourceEnd_ = bufEnd;
-    script->toStringStart_ = toStringStart;
-    script->toStringEnd_ = toStringEnd;
-
-    script->hideScriptFromDebugger_ = options.hideScriptFromDebugger;
-
-#ifdef MOZ_VTUNE
-    script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
-#endif
+
+    if (cx->runtime()->lcovOutput().isEnabled()) {
+        if (!script->initScriptName(cx))
+            return nullptr;
+    }
 
     return script;
 }
 
 bool
 JSScript::initScriptName(JSContext* cx)
 {
     MOZ_ASSERT(!hasScriptName());
@@ -2877,53 +2903,53 @@ InitAtomMap(frontend::AtomIndexMap& indi
 JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox)
 {
     JSFunction* fun = funbox->function();
     if (fun->isInterpretedLazy())
         fun->setUnlazifiedScript(script);
     else
         fun->setScript(script);
 
-    script->funHasExtensibleScope_ = funbox->hasExtensibleScope();
-    script->needsHomeObject_       = funbox->needsHomeObject();
-    script->isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
+    script->bitFields_.funHasExtensibleScope_ = funbox->hasExtensibleScope();
+    script->bitFields_.needsHomeObject_ = funbox->needsHomeObject();
+    script->bitFields_.isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
 
     if (funbox->argumentsHasLocalBinding()) {
         script->setArgumentsHasVarBinding();
         if (funbox->definitelyNeedsArgsObj())
             script->setNeedsArgsObj(true);
     } else {
         MOZ_ASSERT(!funbox->definitelyNeedsArgsObj());
     }
-    script->hasMappedArgsObj_ = funbox->hasMappedArgsObj();
-
-    script->functionHasThisBinding_ = funbox->hasThisBinding();
-    script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
+    script->bitFields_.hasMappedArgsObj_ = funbox->hasMappedArgsObj();
+
+    script->bitFields_.functionHasThisBinding_ = funbox->hasThisBinding();
+    script->bitFields_.functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
 
     script->funLength_ = funbox->length;
 
     script->setGeneratorKind(funbox->generatorKind());
     script->setAsyncKind(funbox->asyncKind());
     if (funbox->hasRest())
         script->setHasRest();
 
     PositionalFormalParameterIter fi(script);
     while (fi && !fi.closedOver())
         fi++;
-    script->funHasAnyAliasedFormal_ = !!fi;
+    script->bitFields_.funHasAnyAliasedFormal_ = !!fi;
 
     script->setHasInnerFunctions(funbox->hasInnerFunctions());
 }
 
 /* static */ void
 JSScript::initFromModuleContext(HandleScript script)
 {
-    script->funHasExtensibleScope_ = false;
-    script->needsHomeObject_ = false;
-    script->isDerivedClassConstructor_ = false;
+    script->bitFields_.funHasExtensibleScope_ = false;
+    script->bitFields_.needsHomeObject_ = false;
+    script->bitFields_.isDerivedClassConstructor_ = false;
     script->funLength_ = 0;
 
     script->setGeneratorKind(GeneratorKind::NotGenerator);
 
     // Since modules are only run once, mark the script so that initializers
     // created within it may be given more precise types.
     script->setTreatAsRunOnce();
     MOZ_ASSERT(!script->hasRunOnce());
@@ -2972,31 +2998,32 @@ JSScript::fullyInitFromEmitter(JSContext
     if (bce->objectList.length != 0)
         bce->objectList.finish(script->objects());
     if (bce->scopeList.length() != 0)
         bce->scopeList.finish(script->scopes());
     if (bce->tryNoteList.length() != 0)
         bce->tryNoteList.finish(script->trynotes());
     if (bce->scopeNoteList.length() != 0)
         bce->scopeNoteList.finish(script->scopeNotes(), prologueLength);
-    script->strict_ = bce->sc->strict();
-    script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
-    script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
-    script->hasSingletons_ = bce->hasSingletons;
+    script->bitFields_.strict_ = bce->sc->strict();
+    script->bitFields_.explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
+    script->bitFields_.bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
+    script->bitFields_.hasSingletons_ = bce->hasSingletons;
 
     uint64_t nslots = bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
     if (nslots > UINT32_MAX) {
         bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
         return false;
     }
 
     script->nfixed_ = bce->maxFixedSlots;
     script->nslots_ = nslots;
     script->bodyScopeIndex_ = bce->bodyScopeIndex;
-    script->hasNonSyntacticScope_ = bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
+    script->bitFields_.hasNonSyntacticScope_ =
+        bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
 
     if (bce->sc->isFunctionBox())
         initFromFunctionBox(script, bce->sc->asFunctionBox());
     else if (bce->sc->isModuleContext())
         initFromModuleContext(script);
 
     // Copy yield offsets last, as the generator kind is set in
     // initFromFunctionBox.
@@ -3533,36 +3560,36 @@ js::detail::CopyScript(JSContext* cx, Ha
     dst->bodyScopeIndex_ = src->bodyScopeIndex_;
     dst->funLength_ = src->funLength();
     dst->nTypeSets_ = src->nTypeSets();
     if (src->argumentsHasVarBinding()) {
         dst->setArgumentsHasVarBinding();
         if (src->analyzedArgsUsage())
             dst->setNeedsArgsObj(src->needsArgsObj());
     }
-    dst->hasMappedArgsObj_ = src->hasMappedArgsObj();
-    dst->functionHasThisBinding_ = src->functionHasThisBinding();
-    dst->functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
+    dst->bitFields_.hasMappedArgsObj_ = src->hasMappedArgsObj();
+    dst->bitFields_.functionHasThisBinding_ = src->functionHasThisBinding();
+    dst->bitFields_.functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
     dst->cloneHasArray(src);
-    dst->strict_ = src->strict();
-    dst->explicitUseStrict_ = src->explicitUseStrict();
-    dst->hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
-    dst->bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
-    dst->funHasExtensibleScope_ = src->funHasExtensibleScope();
-    dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
-    dst->hasSingletons_ = src->hasSingletons();
-    dst->treatAsRunOnce_ = src->treatAsRunOnce();
-    dst->hasInnerFunctions_ = src->hasInnerFunctions();
+    dst->bitFields_.strict_ = src->strict();
+    dst->bitFields_.explicitUseStrict_ = src->explicitUseStrict();
+    dst->bitFields_.hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
+    dst->bitFields_.bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
+    dst->bitFields_.funHasExtensibleScope_ = src->funHasExtensibleScope();
+    dst->bitFields_.funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
+    dst->bitFields_.hasSingletons_ = src->hasSingletons();
+    dst->bitFields_.treatAsRunOnce_ = src->treatAsRunOnce();
+    dst->bitFields_.hasInnerFunctions_ = src->hasInnerFunctions();
     dst->setGeneratorKind(src->generatorKind());
-    dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
-    dst->needsHomeObject_ = src->needsHomeObject();
-    dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
-    dst->isAsync_ = src->isAsync_;
-    dst->hasRest_ = src->hasRest_;
-    dst->hideScriptFromDebugger_ = src->hideScriptFromDebugger_;
+    dst->bitFields_.isDerivedClassConstructor_ = src->isDerivedClassConstructor();
+    dst->bitFields_.needsHomeObject_ = src->needsHomeObject();
+    dst->bitFields_.isDefaultClassConstructor_ = src->isDefaultClassConstructor();
+    dst->bitFields_.isAsync_ = src->bitFields_.isAsync_;
+    dst->bitFields_.hasRest_ = src->bitFields_.hasRest_;
+    dst->bitFields_.hideScriptFromDebugger_ = src->bitFields_.hideScriptFromDebugger_;
 
     if (nconsts != 0) {
         GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
         dst->consts()->vector = vector;
         for (unsigned i = 0; i < nconsts; ++i)
             MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom());
     }
     if (nobjects != 0) {
@@ -3695,59 +3722,59 @@ js::CloneScriptIntoFunction(JSContext* c
         fun->initScript(dst);
 
     return dst;
 }
 
 DebugScript*
 JSScript::debugScript()
 {
-    MOZ_ASSERT(hasDebugScript_);
+    MOZ_ASSERT(bitFields_.hasDebugScript_);
     DebugScriptMap* map = compartment()->debugScriptMap;
     MOZ_ASSERT(map);
     DebugScriptMap::Ptr p = map->lookup(this);
     MOZ_ASSERT(p);
     return p->value();
 }
 
 DebugScript*
 JSScript::releaseDebugScript()
 {
-    MOZ_ASSERT(hasDebugScript_);
+    MOZ_ASSERT(bitFields_.hasDebugScript_);
     DebugScriptMap* map = compartment()->debugScriptMap;
     MOZ_ASSERT(map);
     DebugScriptMap::Ptr p = map->lookup(this);
     MOZ_ASSERT(p);
     DebugScript* debug = p->value();
     map->remove(p);
-    hasDebugScript_ = false;
+    bitFields_.hasDebugScript_ = false;
     return debug;
 }
 
 void
 JSScript::destroyDebugScript(FreeOp* fop)
 {
-    if (hasDebugScript_) {
+    if (bitFields_.hasDebugScript_) {
 #ifdef DEBUG
         for (jsbytecode* pc = code(); pc < codeEnd(); pc++) {
             if (BreakpointSite* site = getBreakpointSite(pc)) {
                 /* Breakpoints are swept before finalization. */
                 MOZ_ASSERT(site->firstBreakpoint() == nullptr);
                 MOZ_ASSERT(getBreakpointSite(pc) == nullptr);
             }
         }
 #endif
         fop->free_(releaseDebugScript());
     }
 }
 
 bool
 JSScript::ensureHasDebugScript(JSContext* cx)
 {
-    if (hasDebugScript_)
+    if (bitFields_.hasDebugScript_)
         return true;
 
     size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
     DebugScript* debug = (DebugScript*) zone()->pod_calloc<uint8_t>(nbytes);
     if (!debug)
         return false;
 
     /* Create compartment's debugScriptMap if necessary. */
@@ -3761,17 +3788,17 @@ JSScript::ensureHasDebugScript(JSContext
         }
         compartment()->debugScriptMap = map;
     }
 
     if (!map->putNew(this, debug)) {
         js_free(debug);
         return false;
     }
-    hasDebugScript_ = true; // safe to set this;  we can't fail after this point
+    bitFields_.hasDebugScript_ = true; // safe to set this;  we can't fail after this point
 
     /*
      * Ensure that any Interpret() instances running on this script have
      * interrupts enabled. The interrupts must stay enabled until the
      * debug state is destroyed.
      */
     for (ActivationIterator iter(cx); !iter.done(); ++iter) {
         if (iter->isInterpreter())
@@ -4028,26 +4055,26 @@ JSScript::innermostScope(jsbytecode* pc)
     if (Scope* scope = lookupScope(pc))
         return scope;
     return bodyScope();
 }
 
 void
 JSScript::setArgumentsHasVarBinding()
 {
-    argsHasVarBinding_ = true;
-    needsArgsAnalysis_ = true;
+    bitFields_.argsHasVarBinding_ = true;
+    bitFields_.needsArgsAnalysis_ = true;
 }
 
 void
 JSScript::setNeedsArgsObj(bool needsArgsObj)
 {
     MOZ_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
-    needsArgsAnalysis_ = false;
-    needsArgsObj_ = needsArgsObj;
+    bitFields_.needsArgsAnalysis_ = false;
+    bitFields_.needsArgsObj_ = needsArgsObj;
 }
 
 void
 js::SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame,
                             HandleScript script, JSObject* argsobj)
 {
     /*
      * Replace any optimized arguments in the frame with an explicit arguments
@@ -4100,17 +4127,17 @@ JSScript::argumentsOptimizationFailed(JS
      * argsobj.
      */
     if (script->needsArgsObj())
         return true;
 
     MOZ_ASSERT(!script->isGenerator());
     MOZ_ASSERT(!script->isAsync());
 
-    script->needsArgsObj_ = true;
+    script->bitFields_.needsArgsObj_ = true;
 
     /*
      * Since we can't invalidate baseline scripts, set a flag that's checked from
      * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS
      * should create an arguments object next time.
      */
     if (script->hasBaselineScript())
         script->baselineScript()->setNeedsArgsObj();
@@ -4441,17 +4468,17 @@ JSScript::AutoDelazify::holdScript(JS::H
             // can't use JSAutoRealm: it could cause races. Functions in the
             // self-hosting compartment will never be lazy, so we can safely
             // assume we don't have to delazify.
             script_ = fun->nonLazyScript();
         } else {
             JSAutoRealm ar(cx_, fun);
             script_ = JSFunction::getOrCreateScript(cx_, fun);
             if (script_) {
-                oldDoNotRelazify_ = script_->doNotRelazify_;
+                oldDoNotRelazify_ = script_->bitFields_.doNotRelazify_;
                 script_->setDoNotRelazify(true);
             }
         }
     }
 }
 
 void
 JSScript::AutoDelazify::dropScript()
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -895,79 +895,78 @@ SweepScriptData(JSRuntime* rt);
 
 extern void
 FreeScriptData(JSRuntime* rt);
 
 } /* namespace js */
 
 class JSScript : public js::gc::TenuredCell
 {
-    template <js::XDRMode mode>
-    friend
-    js::XDRResult
-    js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope,
-                  js::HandleScriptSourceObject sourceObject, js::HandleFunction fun,
-                  js::MutableHandleScript scriptp);
-
-    friend bool
-    js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst,
-                           js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
-
   private:
     // Pointer to baseline->method()->raw(), ion->method()->raw(), a wasm jit
     // entry, the JIT's EnterInterpreter stub, or the lazy link stub. Must be
     // non-null.
-    uint8_t* jitCodeRaw_;
-    uint8_t* jitCodeSkipArgCheck_;
-
-    js::SharedScriptData* scriptData_;
+    uint8_t* jitCodeRaw_ = nullptr;
+    uint8_t* jitCodeSkipArgCheck_ = nullptr;
+
+    js::SharedScriptData* scriptData_ = nullptr;
+
   public:
-    uint8_t*        data;      /* pointer to variable-length data array (see
-                                   comment above Create() for details) */
-
-    JS::Realm* realm_;
+    // Pointer to variable-length data array (see comment above Create() for
+    // details).
+    uint8_t* data = nullptr;
+
+    JS::Realm* realm_ = nullptr;
 
   private:
     /* Persistent type information retained across GCs. */
-    js::TypeScript* types_;
+    js::TypeScript* types_ = nullptr;
 
     // This script's ScriptSourceObject, or a CCW thereof.
     //
     // (When we clone a JSScript into a new compartment, we don't clone its
     // source object. Instead, the clone refers to a wrapper.)
-    js::GCPtrObject sourceObject_;
+    js::GCPtrObject sourceObject_ = {};
 
     /*
      * Information attached by Ion. Nexto a valid IonScript this could be
      * ION_DISABLED_SCRIPT, ION_COMPILING_SCRIPT or ION_PENDING_SCRIPT.
      * The later is a ion compilation that is ready, but hasn't been linked
      * yet.
      */
-    js::jit::IonScript* ion;
+    js::jit::IonScript* ion = nullptr;
 
     /* Information attached by Baseline. */
-    js::jit::BaselineScript* baseline;
+    js::jit::BaselineScript* baseline = nullptr;
 
     /* Information used to re-lazify a lazily-parsed interpreted function. */
-    js::LazyScript* lazyScript;
+    js::LazyScript* lazyScript = nullptr;
 
     // 32-bit fields.
 
-    uint32_t        dataSize_;  /* size of the used part of the data array */
-
-    uint32_t        lineno_;    /* base line number of script */
-    uint32_t        column_;    /* base column of script, optionally set */
-
-    uint32_t        mainOffset_;/* offset of main entry point from code, after
-                                   predef'ing prologue */
-
-    uint32_t        nfixed_;    /* fixed frame slots */
-    uint32_t        nslots_;    /* slots plus maximum stack depth */
-
-    uint32_t        bodyScopeIndex_; /* index into the scopes array of the body scope */
+    /* Size of the used part of the data array. */
+    uint32_t dataSize_ = 0;
+
+    /* Base line number of script. */
+    uint32_t lineno_ = 0;
+
+    /* Base column of script, optionally set. */
+    uint32_t column_ = 0;
+
+    /* Offset of main entry point from code, after predef'ing prologue. */
+    uint32_t mainOffset_ = 0;
+
+    /* Fixed frame slots. */
+    uint32_t nfixed_ = 0;
+
+    /* Slots plus maximum stack depth. */
+    uint32_t nslots_ = 0;
+
+    /* Index into the scopes array of the body scope */
+    uint32_t bodyScopeIndex_ = 0;
 
     // Range of characters in scriptSource which contains this script's
     // source, that is, the range used by the Parser to produce this script.
     //
     // Most scripted functions have sourceStart_ == toStringStart_ and
     // sourceEnd_ == toStringEnd_. However, for functions with extra
     // qualifiers (e.g. generators, async) and for class constructors (which
     // need to return the entire class source), their values differ.
@@ -985,193 +984,237 @@ class JSScript : public js::gc::TenuredC
     // offset is used.
     //
     //   class C { constructor() { this.field = 42; } }
     //   ^         ^                                 ^ ^
     //   |         |                                 | `---------`
     //   |         sourceStart_                      sourceEnd_  |
     //   |                                                       |
     //   toStringStart_                                          toStringEnd_
-    uint32_t        sourceStart_;
-    uint32_t        sourceEnd_;
-    uint32_t        toStringStart_;
-    uint32_t        toStringEnd_;
+    uint32_t sourceStart_ = 0;
+    uint32_t sourceEnd_ = 0;
+    uint32_t toStringStart_ = 0;
+    uint32_t toStringEnd_ = 0;
 
 #ifdef MOZ_VTUNE
     // Unique Method ID passed to the VTune profiler, or 0 if unset.
     // Allows attribution of different jitcode to the same source script.
-    uint32_t        vtuneMethodId_;
+    uint32_t vtuneMethodId_ = 0;
     // Extra padding to maintain JSScript as a multiple of gc::CellAlignBytes.
-    uint32_t        __vtune_unused_padding_;
+    uint32_t __vtune_unused_padding_;
 #endif
 
     // Number of times the script has been called or has had backedges taken.
     // When running in ion, also increased for any inlined scripts. Reset if
     // the script's JIT code is forcibly discarded.
-    mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount;
+    mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount = {};
 
     // 16-bit fields.
 
-    uint16_t        warmUpResetCount; /* Number of times the |warmUpCount| was
-                                       * forcibly discarded. The counter is reset when
-                                       * a script is successfully jit-compiled. */
-
-    uint16_t        funLength_; /* ES6 function length */
-
-    uint16_t        nTypeSets_; /* number of type sets used in this script for
-                                   dynamic type monitoring */
+    /**
+     * Number of times the |warmUpCount| was forcibly discarded. The counter is
+     * reset when a script is successfully jit-compiled.
+     */
+    uint16_t warmUpResetCount = 0;
+
+    /* ES6 function length. */
+    uint16_t funLength_ = 0;
+
+    /* Number of type sets used in this script for dynamic type monitoring. */
+    uint16_t nTypeSets_ = 0;
 
     // Bit fields.
 
   public:
     // The kinds of the optional arrays.
     enum ArrayKind {
         CONSTS,
         OBJECTS,
         TRYNOTES,
         SCOPENOTES,
         ARRAY_KIND_BITS
     };
 
   private:
-    // The bits in this field indicate the presence/non-presence of several
-    // optional arrays in |data|.  See the comments above Create() for details.
-    uint8_t hasArrayBits:ARRAY_KIND_BITS;
-
-    // 1-bit fields.
-
-    // No need for result value of last expression statement.
-    bool noScriptRval_:1;
-
-    // Code is in strict mode.
-    bool strict_:1;
-
-    // Code has "use strict"; explicitly.
-    bool explicitUseStrict_:1;
-
-    // True if the script has a non-syntactic scope on its dynamic scope chain.
-    // That is, there are objects about which we know nothing between the
-    // outermost syntactic scope and the global.
-    bool hasNonSyntacticScope_:1;
-
-    // see Parser::selfHostingMode.
-    bool selfHosted_:1;
-
-    // See FunctionBox.
-    bool bindingsAccessedDynamically_:1;
-    bool funHasExtensibleScope_:1;
-
-    // True if any formalIsAliased(i).
-    bool funHasAnyAliasedFormal_:1;
-
-    // Have warned about uses of undefined properties in this script.
-    bool warnedAboutUndefinedProp_:1;
-
-    // Script has singleton objects.
-    bool hasSingletons_:1;
-
-    // Script is a lambda to treat as running once or a global or eval script
-    // that will only run once.  Which one it is can be disambiguated by
-    // checking whether function() is null.
-    bool treatAsRunOnce_:1;
-
-    // If treatAsRunOnce, whether script has executed.
-    bool hasRunOnce_:1;
-
-    // Script has been reused for a clone.
-    bool hasBeenCloned_:1;
-
-    // Script came from eval(), and is still active.
-    bool isActiveEval_:1;
-
-    // Script came from eval(), and is in eval cache.
-    bool isCachedEval_:1;
-
-    // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
-    bool isLikelyConstructorWrapper_:1;
-
-    // IonMonkey compilation hints.
-    bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
-    bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
-    bool hadFrequentBailouts_:1;
-    bool hadOverflowBailout_:1;
-    bool uninlineable_:1;    /* explicitly marked as uninlineable */
-
-    // Idempotent cache has triggered invalidation.
-    bool invalidatedIdempotentCache_:1;
-
-    // Lexical check did fail and bail out.
-    bool failedLexicalCheck_:1;
-
-    // Script has an entry in JSCompartment::scriptCountsMap.
-    bool hasScriptCounts_:1;
-
-    // Script has an entry in JSCompartment::debugScriptMap.
-    bool hasDebugScript_:1;
-
-    // Freeze constraints for stack type sets have been generated.
-    bool hasFreezeConstraints_:1;
-
-    /* See comments below. */
-    bool argsHasVarBinding_:1;
-    bool needsArgsAnalysis_:1;
-    bool needsArgsObj_:1;
-    bool functionHasThisBinding_:1;
-    bool functionHasExtraBodyVarScope_:1;
-
-    // Whether the arguments object for this script, if it needs one, should be
-    // mapped (alias formal parameters).
-    bool hasMappedArgsObj_:1;
-
-    // Generation for this script's TypeScript. If out of sync with the
-    // TypeZone's generation, the TypeScript needs to be swept.
-    //
-    // This should be a uint32 but is instead a bool so that MSVC packs it
-    // correctly.
-    bool typesGeneration_:1;
-
-    // Do not relazify this script. This is used by the relazify() testing
-    // function for scripts that are on the stack and also by the AutoDelazify
-    // RAII class. Usually we don't relazify functions in compartments with
-    // scripts on the stack, but the relazify() testing function overrides that,
-    // and sometimes we're working with a cross-compartment function and need to
-    // keep it from relazifying.
-    bool doNotRelazify_:1;
-
-    // Script contains inner functions. Used to check if we can relazify the
-    // script.
-    bool hasInnerFunctions_:1;
-
-    bool needsHomeObject_:1;
-
-    bool isDerivedClassConstructor_:1;
-    bool isDefaultClassConstructor_:1;
-
-    // True if this function is a generator function or async generator.
-    bool isGenerator_:1;
-
-    // True if this function is an async function or async generator.
-    bool isAsync_:1;
-
-    bool hasRest_:1;
-
-    // True if the debugger's onNewScript hook has not yet been called.
-    bool hideScriptFromDebugger_:1;
+    struct BitFields
+    {
+        /*
+         * Bit-fields can't have member initializers til C++2a, i.e. probably
+         * C++20, so we can't initialize these to zero in place.  Instead we
+         * braced-init this to all zeroes in the JSScript constructor, then
+         * custom-assign particular bit-fields in the constructor body.
+         */
+
+        // The bits in this field indicate the presence/non-presence of several
+        // optional arrays in |data|.  See the comments above Create() for details.
+        uint8_t hasArrayBits_ : ARRAY_KIND_BITS;
+
+        /*
+         * All remaining bit-fields are single-bit bools.
+         */
+
+        // No need for result value of last expression statement.
+        bool noScriptRval_ : 1;
+
+        // Code is in strict mode.
+        bool strict_ : 1;
+
+        // Code has "use strict"; explicitly.
+        bool explicitUseStrict_ : 1;
+
+        // True if the script has a non-syntactic scope on its dynamic scope chain.
+        // That is, there are objects about which we know nothing between the
+        // outermost syntactic scope and the global.
+        bool hasNonSyntacticScope_ : 1;
+
+        // see Parser::selfHostingMode.
+        bool selfHosted_ : 1;
+
+        // See FunctionBox.
+        bool bindingsAccessedDynamically_ : 1;
+        bool funHasExtensibleScope_ : 1;
+
+        // True if any formalIsAliased(i).
+        bool funHasAnyAliasedFormal_ : 1;
+
+        // Have warned about uses of undefined properties in this script.
+        bool warnedAboutUndefinedProp_ : 1;
+
+        // Script has singleton objects.
+        bool hasSingletons_ : 1;
+
+        // Script is a lambda to treat as running once or a global or eval script
+        // that will only run once.  Which one it is can be disambiguated by
+        // checking whether function() is null.
+        bool treatAsRunOnce_ : 1;
+
+        // If treatAsRunOnce, whether script has executed.
+        bool hasRunOnce_ : 1;
+
+        // Script has been reused for a clone.
+        bool hasBeenCloned_ : 1;
+
+        // Script came from eval(), and is still active.
+        bool isActiveEval_ : 1;
+
+        // Script came from eval(), and is in eval cache.
+        bool isCachedEval_ : 1;
+
+        // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
+        bool isLikelyConstructorWrapper_ : 1;
+
+        // IonMonkey compilation hints.
+
+        /* Script has had hoisted bounds checks fail. */
+        bool failedBoundsCheck_ : 1;
+
+        /* Script has had hoisted shape guard fail. */
+        bool failedShapeGuard_ : 1;
+
+        bool hadFrequentBailouts_ : 1;
+        bool hadOverflowBailout_ : 1;
+
+        /* Explicitly marked as uninlineable. */
+        bool uninlineable_ : 1;
+
+        // Idempotent cache has triggered invalidation.
+        bool invalidatedIdempotentCache_ : 1;
+
+        // Lexical check did fail and bail out.
+        bool failedLexicalCheck_ : 1;
+
+        // Script has an entry in JSCompartment::scriptCountsMap.
+        bool hasScriptCounts_ : 1;
+
+        // Script has an entry in JSCompartment::debugScriptMap.
+        bool hasDebugScript_ : 1;
+
+        // Freeze constraints for stack type sets have been generated.
+        bool hasFreezeConstraints_ : 1;
+
+        /* See comments below. */
+        bool argsHasVarBinding_ : 1;
+        bool needsArgsAnalysis_ : 1;
+        bool needsArgsObj_ : 1;
+        bool functionHasThisBinding_ : 1;
+        bool functionHasExtraBodyVarScope_ : 1;
+
+        // Whether the arguments object for this script, if it needs one, should be
+        // mapped (alias formal parameters).
+        bool hasMappedArgsObj_ : 1;
+
+        // Generation for this script's TypeScript. If out of sync with the
+        // TypeZone's generation, the TypeScript needs to be swept.
+        //
+        // This should be a uint32 but is instead a bool so that MSVC packs it
+        // correctly.
+        bool typesGeneration_ : 1;
+
+        // Do not relazify this script. This is used by the relazify() testing
+        // function for scripts that are on the stack and also by the AutoDelazify
+        // RAII class. Usually we don't relazify functions in compartments with
+        // scripts on the stack, but the relazify() testing function overrides that,
+        // and sometimes we're working with a cross-compartment function and need to
+        // keep it from relazifying.
+        bool doNotRelazify_ : 1;
+
+        // Script contains inner functions. Used to check if we can relazify the
+        // script.
+        bool hasInnerFunctions_ : 1;
+
+        bool needsHomeObject_ : 1;
+
+        bool isDerivedClassConstructor_ : 1;
+        bool isDefaultClassConstructor_ : 1;
+
+        // True if this function is a generator function or async generator.
+        bool isGenerator_ : 1;
+
+        // True if this function is an async function or async generator.
+        bool isAsync_ : 1;
+
+        bool hasRest_ : 1;
+
+        // True if the debugger's onNewScript hook has not yet been called.
+        bool hideScriptFromDebugger_ : 1;
+    } bitFields_;
 
     // Add padding so JSScript is gc::Cell aligned. Make padding protected
     // instead of private to suppress -Wunused-private-field compiler warnings.
   protected:
 #if JS_BITS_PER_WORD == 32
     uint32_t padding_;
 #endif
 
     //
     // End of fields.  Start methods.
     //
 
+  private:
+    template <js::XDRMode mode>
+    friend
+    js::XDRResult
+    js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope,
+                  js::HandleScriptSourceObject sourceObject, js::HandleFunction fun,
+                  js::MutableHandleScript scriptp);
+
+    friend bool
+    js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst,
+                           js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
+
+  private:
+    JSScript(JS::Realm* realm, uint8_t* stubEntry, const JS::ReadOnlyCompileOptions& options,
+             js::HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
+             uint32_t toStringStart, uint32_t toStringend);
+
+    static JSScript* createInitialized(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
+                                       js::HandleObject sourceObject,
+                                       uint32_t bufStart, uint32_t bufEnd,
+                                       uint32_t toStringStart, uint32_t toStringEnd);
+
   public:
     static JSScript* Create(JSContext* cx,
                             const JS::ReadOnlyCompileOptions& options,
                             js::HandleObject sourceObject,
                             uint32_t sourceStart, uint32_t sourceEnd,
                             uint32_t toStringStart, uint32_t toStringEnd);
 
     // Three ways ways to initialize a JSScript. Callers of partiallyInit()
@@ -1322,234 +1365,236 @@ class JSScript : public js::gc::TenuredC
         return toStringStart_;
     }
 
     uint32_t toStringEnd() const {
         return toStringEnd_;
     }
 
     bool noScriptRval() const {
-        return noScriptRval_;
+        return bitFields_.noScriptRval_;
     }
 
     bool strict() const {
-        return strict_;
+        return bitFields_.strict_;
     }
 
-    bool explicitUseStrict() const { return explicitUseStrict_; }
+    bool explicitUseStrict() const { return bitFields_.explicitUseStrict_; }
 
     bool hasNonSyntacticScope() const {
-        return hasNonSyntacticScope_;
+        return bitFields_.hasNonSyntacticScope_;
     }
 
-    bool selfHosted() const { return selfHosted_; }
-    bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
+    bool selfHosted() const { return bitFields_.selfHosted_; }
+    bool bindingsAccessedDynamically() const { return bitFields_.bindingsAccessedDynamically_; }
     bool funHasExtensibleScope() const {
-        return funHasExtensibleScope_;
+        return bitFields_.funHasExtensibleScope_;
     }
     bool funHasAnyAliasedFormal() const {
-        return funHasAnyAliasedFormal_;
+        return bitFields_.funHasAnyAliasedFormal_;
     }
 
-    bool hasSingletons() const { return hasSingletons_; }
+    bool hasSingletons() const { return bitFields_.hasSingletons_; }
     bool treatAsRunOnce() const {
-        return treatAsRunOnce_;
+        return bitFields_.treatAsRunOnce_;
     }
-    bool hasRunOnce() const { return hasRunOnce_; }
-    bool hasBeenCloned() const { return hasBeenCloned_; }
-
-    void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
-    void setHasRunOnce() { hasRunOnce_ = true; }
-    void setHasBeenCloned() { hasBeenCloned_ = true; }
-
-    bool isActiveEval() const { return isActiveEval_; }
-    bool isCachedEval() const { return isCachedEval_; }
+    bool hasRunOnce() const { return bitFields_.hasRunOnce_; }
+    bool hasBeenCloned() const { return bitFields_.hasBeenCloned_; }
+
+    void setTreatAsRunOnce() { bitFields_.treatAsRunOnce_ = true; }
+    void setHasRunOnce() { bitFields_.hasRunOnce_ = true; }
+    void setHasBeenCloned() { bitFields_.hasBeenCloned_ = true; }
+
+    bool isActiveEval() const { return bitFields_.isActiveEval_; }
+    bool isCachedEval() const { return bitFields_.isCachedEval_; }
 
     void cacheForEval() {
-        MOZ_ASSERT(isActiveEval() && !isCachedEval());
-        isActiveEval_ = false;
-        isCachedEval_ = true;
+        MOZ_ASSERT(isActiveEval());
+        MOZ_ASSERT(!isCachedEval());
+        bitFields_.isActiveEval_ = false;
+        bitFields_.isCachedEval_ = true;
         // IsEvalCacheCandidate will make sure that there's nothing in this
         // script that would prevent reexecution even if isRunOnce is
         // true.  So just pretend like we never ran this script.
-        hasRunOnce_ = false;
+        bitFields_.hasRunOnce_ = false;
     }
 
     void uncacheForEval() {
-        MOZ_ASSERT(isCachedEval() && !isActiveEval());
-        isCachedEval_ = false;
-        isActiveEval_ = true;
+        MOZ_ASSERT(isCachedEval());
+        MOZ_ASSERT(!isActiveEval());
+        bitFields_.isCachedEval_ = false;
+        bitFields_.isActiveEval_ = true;
     }
 
-    void setActiveEval() { isActiveEval_ = true; }
+    void setActiveEval() { bitFields_.isActiveEval_ = true; }
 
     bool isLikelyConstructorWrapper() const {
-        return isLikelyConstructorWrapper_;
+        return bitFields_.isLikelyConstructorWrapper_;
     }
-    void setLikelyConstructorWrapper() { isLikelyConstructorWrapper_ = true; }
+    void setLikelyConstructorWrapper() { bitFields_.isLikelyConstructorWrapper_ = true; }
 
     bool failedBoundsCheck() const {
-        return failedBoundsCheck_;
+        return bitFields_.failedBoundsCheck_;
     }
     bool failedShapeGuard() const {
-        return failedShapeGuard_;
+        return bitFields_.failedShapeGuard_;
     }
     bool hadFrequentBailouts() const {
-        return hadFrequentBailouts_;
+        return bitFields_.hadFrequentBailouts_;
     }
     bool hadOverflowBailout() const {
-        return hadOverflowBailout_;
+        return bitFields_.hadOverflowBailout_;
     }
     bool uninlineable() const {
-        return uninlineable_;
+        return bitFields_.uninlineable_;
     }
     bool invalidatedIdempotentCache() const {
-        return invalidatedIdempotentCache_;
+        return bitFields_.invalidatedIdempotentCache_;
     }
     bool failedLexicalCheck() const {
-        return failedLexicalCheck_;
+        return bitFields_.failedLexicalCheck_;
     }
     bool isDefaultClassConstructor() const {
-        return isDefaultClassConstructor_;
+        return bitFields_.isDefaultClassConstructor_;
     }
 
-    void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
-    void setFailedShapeGuard() { failedShapeGuard_ = true; }
-    void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
-    void setHadOverflowBailout() { hadOverflowBailout_ = true; }
-    void setUninlineable() { uninlineable_ = true; }
-    void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
-    void setFailedLexicalCheck() { failedLexicalCheck_ = true; }
-    void setIsDefaultClassConstructor() { isDefaultClassConstructor_ = true; }
-
-    bool hasScriptCounts() const { return hasScriptCounts_; }
+    void setFailedBoundsCheck() { bitFields_.failedBoundsCheck_ = true; }
+    void setFailedShapeGuard() { bitFields_.failedShapeGuard_ = true; }
+    void setHadFrequentBailouts() { bitFields_.hadFrequentBailouts_ = true; }
+    void setHadOverflowBailout() { bitFields_.hadOverflowBailout_ = true; }
+    void setUninlineable() { bitFields_.uninlineable_ = true; }
+    void setInvalidatedIdempotentCache() { bitFields_.invalidatedIdempotentCache_ = true; }
+    void setFailedLexicalCheck() { bitFields_.failedLexicalCheck_ = true; }
+    void setIsDefaultClassConstructor() { bitFields_.isDefaultClassConstructor_ = true; }
+
+    bool hasScriptCounts() const { return bitFields_.hasScriptCounts_; }
     bool hasScriptName();
 
-    bool hasFreezeConstraints() const { return hasFreezeConstraints_; }
-    void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
-
-    bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
-    void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
+    bool hasFreezeConstraints() const { return bitFields_.hasFreezeConstraints_; }
+    void setHasFreezeConstraints() { bitFields_.hasFreezeConstraints_ = true; }
+
+    bool warnedAboutUndefinedProp() const { return bitFields_.warnedAboutUndefinedProp_; }
+    void setWarnedAboutUndefinedProp() { bitFields_.warnedAboutUndefinedProp_ = true; }
 
     /* See ContextFlags::funArgumentsHasLocalBinding comment. */
     bool argumentsHasVarBinding() const {
-        return argsHasVarBinding_;
+        return bitFields_.argsHasVarBinding_;
     }
     void setArgumentsHasVarBinding();
     bool argumentsAliasesFormals() const {
         return argumentsHasVarBinding() && hasMappedArgsObj();
     }
 
     js::GeneratorKind generatorKind() const {
-        return isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
+        return bitFields_.isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
     }
-    bool isGenerator() const { return isGenerator_; }
+    bool isGenerator() const { return bitFields_.isGenerator_; }
     void setGeneratorKind(js::GeneratorKind kind) {
         // A script only gets its generator kind set as part of initialization,
         // so it can only transition from not being a generator.
         MOZ_ASSERT(!isGenerator());
-        isGenerator_ = kind == js::GeneratorKind::Generator;
+        bitFields_.isGenerator_ = kind == js::GeneratorKind::Generator;
     }
 
     js::FunctionAsyncKind asyncKind() const {
-        return isAsync_
+        return bitFields_.isAsync_
                ? js::FunctionAsyncKind::AsyncFunction
                : js::FunctionAsyncKind::SyncFunction;
     }
     bool isAsync() const {
-        return isAsync_;
+        return bitFields_.isAsync_;
     }
 
     void setAsyncKind(js::FunctionAsyncKind kind) {
-        isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction;
+        bitFields_.isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction;
     }
 
     bool hasRest() const {
-        return hasRest_;
+        return bitFields_.hasRest_;
     }
     void setHasRest() {
-        hasRest_ = true;
+        bitFields_.hasRest_ = true;
     }
 
     bool hideScriptFromDebugger() const {
-        return hideScriptFromDebugger_;
+        return bitFields_.hideScriptFromDebugger_;
     }
     void clearHideScriptFromDebugger() {
-        hideScriptFromDebugger_ = false;
+        bitFields_.hideScriptFromDebugger_ = false;
     }
 
     void setNeedsHomeObject() {
-        needsHomeObject_ = true;
+        bitFields_.needsHomeObject_ = true;
     }
     bool needsHomeObject() const {
-        return needsHomeObject_;
+        return bitFields_.needsHomeObject_;
     }
 
     bool isDerivedClassConstructor() const {
-        return isDerivedClassConstructor_;
+        return bitFields_.isDerivedClassConstructor_;
     }
 
     /*
      * As an optimization, even when argsHasLocalBinding, the function prologue
      * may not need to create an arguments object. This is determined by
      * needsArgsObj which is set by AnalyzeArgumentsUsage. When !needsArgsObj,
      * the prologue may simply write MagicValue(JS_OPTIMIZED_ARGUMENTS) to
      * 'arguments's slot and any uses of 'arguments' will be guaranteed to
      * handle this magic value. To avoid spurious arguments object creation, we
      * maintain the invariant that needsArgsObj is only called after the script
      * has been analyzed.
      */
-    bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
+    bool analyzedArgsUsage() const { return !bitFields_.needsArgsAnalysis_; }
     inline bool ensureHasAnalyzedArgsUsage(JSContext* cx);
     bool needsArgsObj() const {
         MOZ_ASSERT(analyzedArgsUsage());
-        return needsArgsObj_;
+        return bitFields_.needsArgsObj_;
     }
     void setNeedsArgsObj(bool needsArgsObj);
     static bool argumentsOptimizationFailed(JSContext* cx, js::HandleScript script);
 
     bool hasMappedArgsObj() const {
-        return hasMappedArgsObj_;
+        return bitFields_.hasMappedArgsObj_;
     }
 
     bool functionHasThisBinding() const {
-        return functionHasThisBinding_;
+        return bitFields_.functionHasThisBinding_;
     }
 
     /*
      * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
      * location for the argument. If an arguments object exists AND it's mapped
      * ('arguments' aliases formals), then all access must go through the
      * arguments object. Otherwise, the local slot is the canonical location for
      * the arguments. Note: if a formal is aliased through the scope chain, then
      * script->formalIsAliased and JSOP_*ARG* opcodes won't be emitted at all.
      */
     bool argsObjAliasesFormals() const {
         return needsArgsObj() && hasMappedArgsObj();
     }
 
     uint32_t typesGeneration() const {
-        return (uint32_t) typesGeneration_;
+        return (uint32_t) bitFields_.typesGeneration_;
     }
 
     void setTypesGeneration(uint32_t generation) {
         MOZ_ASSERT(generation <= 1);
-        typesGeneration_ = (bool) generation;
+        bitFields_.typesGeneration_ = (bool) generation;
     }
 
     void setDoNotRelazify(bool b) {
-        doNotRelazify_ = b;
+        bitFields_.doNotRelazify_ = b;
     }
 
     void setHasInnerFunctions(bool b) {
-        hasInnerFunctions_ = b;
+        bitFields_.hasInnerFunctions_ = b;
     }
 
     bool hasInnerFunctions() const {
-        return hasInnerFunctions_;
+        return bitFields_.hasInnerFunctions_;
     }
 
     bool hasAnyIonScript() const {
         return hasIonScript();
     }
 
     bool hasIonScript() const {
         bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT &&
@@ -1604,21 +1649,21 @@ class JSScript : public js::gc::TenuredC
     static constexpr size_t offsetOfJitCodeSkipArgCheck() {
         return offsetof(JSScript, jitCodeSkipArgCheck_);
     }
     uint8_t* jitCodeRaw() const {
         return jitCodeRaw_;
     }
 
     bool isRelazifiable() const {
-        return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
+        return (selfHosted() || lazyScript) && !bitFields_.hasInnerFunctions_ && !types_ &&
                !isGenerator() && !isAsync() &&
                !isDefaultClassConstructor() &&
                !hasBaselineScript() && !hasAnyIonScript() &&
-               !doNotRelazify_;
+               !bitFields_.doNotRelazify_;
     }
     void setLazyScript(js::LazyScript* lazy) {
         lazyScript = lazy;
     }
     js::LazyScript* maybeLazyScript() {
         return lazyScript;
     }
 
@@ -1734,18 +1779,18 @@ class JSScript : public js::gc::TenuredC
     js::Scope* outermostScope() const {
         // The body scope may not be the outermost scope in the script when
         // the decl env scope is present.
         size_t index = 0;
         return getScope(index);
     }
 
     bool functionHasExtraBodyVarScope() const {
-        MOZ_ASSERT_IF(functionHasExtraBodyVarScope_, functionHasParameterExprs());
-        return functionHasExtraBodyVarScope_;
+        MOZ_ASSERT_IF(bitFields_.functionHasExtraBodyVarScope_, functionHasParameterExprs());
+        return bitFields_.functionHasExtraBodyVarScope_;
     }
 
     js::VarScope* functionExtraBodyVarScope() const {
         MOZ_ASSERT(functionHasExtraBodyVarScope());
         for (uint32_t i = 0; i < scopes()->length; i++) {
             js::Scope* scope = getScope(i);
             if (scope->kind() == js::ScopeKind::FunctionBodyVar)
                 return &scope->as<js::VarScope>();
@@ -1815,20 +1860,22 @@ class JSScript : public js::gc::TenuredC
      * sizeOfData() is the size of the block allocated to hold all the data
      * sections (which can be larger than the in-use size).
      */
     size_t computedSizeOfData() const;
     size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
     size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
 
     bool hasArray(ArrayKind kind) const {
-        return hasArrayBits & (1 << kind);
+        return bitFields_.hasArrayBits_ & (1 << kind);
     }
-    void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
-    void cloneHasArray(JSScript* script) { hasArrayBits = script->hasArrayBits; }
+    void setHasArray(ArrayKind kind) { bitFields_.hasArrayBits_ |= (1 << kind); }
+    void cloneHasArray(JSScript* script) {
+        bitFields_.hasArrayBits_ = script->bitFields_.hasArrayBits_;
+    }
 
     bool hasConsts() const       { return hasArray(CONSTS); }
     bool hasObjects() const      { return hasArray(OBJECTS); }
     bool hasTrynotes() const     { return hasArray(TRYNOTES); }
     bool hasScopeNotes() const   { return hasArray(SCOPENOTES); }
     bool hasYieldAndAwaitOffsets() const {
         return isGenerator() || isAsync();
     }
@@ -1993,25 +2040,25 @@ class JSScript : public js::gc::TenuredC
 
     bool ensureHasDebugScript(JSContext* cx);
     js::DebugScript* debugScript();
     js::DebugScript* releaseDebugScript();
     void destroyDebugScript(js::FreeOp* fop);
 
   public:
     bool hasBreakpointsAt(jsbytecode* pc);
-    bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; }
+    bool hasAnyBreakpointsOrStepMode() { return bitFields_.hasDebugScript_; }
 
     // See comment above 'debugMode' in JSCompartment.h for explanation of
     // invariants of debuggee compartments, scripts, and frames.
     inline bool isDebuggee() const;
 
     js::BreakpointSite* getBreakpointSite(jsbytecode* pc)
     {
-        return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
+        return bitFields_.hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
     }
 
     js::BreakpointSite* getOrCreateBreakpointSite(JSContext* cx, jsbytecode* pc);
 
     void destroyBreakpointSite(js::FreeOp* fop, jsbytecode* pc);
 
     void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JSObject* handler);
 
@@ -2019,20 +2066,20 @@ class JSScript : public js::gc::TenuredC
      * Increment or decrement the single-step count. If the count is non-zero
      * then the script is in single-step mode.
      *
      * Only incrementing is fallible, as it could allocate a DebugScript.
      */
     bool incrementStepModeCount(JSContext* cx);
     void decrementStepModeCount(js::FreeOp* fop);
 
-    bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; }
+    bool stepModeEnabled() { return bitFields_.hasDebugScript_ && !!debugScript()->stepMode; }
 
 #ifdef DEBUG
-    uint32_t stepModeCount() { return hasDebugScript_ ? debugScript()->stepMode : 0; }
+    uint32_t stepModeCount() { return bitFields_.hasDebugScript_ ? debugScript()->stepMode : 0; }
 #endif
 
     void finalize(js::FreeOp* fop);
 
     static const JS::TraceKind TraceKind = JS::TraceKind::Script;
 
     void traceChildren(JSTracer* trc);
 
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -23,36 +23,31 @@
 #include "vm/Shape.h"
 #include "vm/TaggedProto.h"
 
 #include "gc/Marking-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
-using mozilla::PodZero;
-
 /////////////////////////////////////////////////////////////////////
 // ObjectGroup
 /////////////////////////////////////////////////////////////////////
 
 ObjectGroup::ObjectGroup(const Class* clasp, TaggedProto proto, JS::Realm* realm,
                          ObjectGroupFlags initialFlags)
+  : clasp_(clasp),
+    proto_(proto),
+    realm_(realm),
+    flags_(initialFlags)
 {
-    PodZero(this);
-
     /* Windows may not appear on prototype chains. */
     MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject()));
     MOZ_ASSERT(JS::StringIsASCII(clasp->name));
 
-    this->clasp_ = clasp;
-    this->proto_ = proto;
-    this->realm_ = realm;
-    this->flags_ = initialFlags;
-
     setGeneration(zone()->types.generation);
 }
 
 void
 ObjectGroup::finalize(FreeOp* fop)
 {
     if (newScriptDontCheckGeneration())
         newScriptDontCheckGeneration()->clear();
@@ -1614,21 +1609,16 @@ ObjectGroup::findAllocationSite(JSContex
 
     return false;
 }
 
 /////////////////////////////////////////////////////////////////////
 // ObjectGroupCompartment
 /////////////////////////////////////////////////////////////////////
 
-ObjectGroupCompartment::ObjectGroupCompartment()
-{
-    PodZero(this);
-}
-
 ObjectGroupCompartment::~ObjectGroupCompartment()
 {
     js_delete(defaultNewTable);
     js_delete(lazyTable);
     js_delete(arrayObjectTable);
     js_delete(plainObjectTable);
     js_delete(allocationSiteTable);
     stringSplitStringGroup = nullptr;
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -82,27 +82,107 @@ enum NewObjectKind {
  * information is sensitive to changes in the property's type. Future changes
  * to the property (whether those uncovered by analysis or those occurring
  * in the VM) will treat these properties like those of any other object group.
  */
 
 /* Type information about an object accessed by a script. */
 class ObjectGroup : public gc::TenuredCell
 {
+  public:
+    class Property;
+
+  private:
+    /* Class shared by objects in this group. */
+    const Class* clasp_; // set by constructor
+
+    /* Prototype shared by objects in this group. */
+    GCPtr<TaggedProto> proto_; // set by constructor
+
+    /* Realm shared by objects in this group. */
+    JS::Realm* realm_;; // set by constructor
+
+    /* Flags for this group. */
+    ObjectGroupFlags flags_; // set by constructor
+
+    // If non-null, holds additional information about this object, whose
+    // format is indicated by the object's addendum kind.
+    void* addendum_ = nullptr;
+
+    /*
+     * Properties of this object.
+     *
+     * The type sets in the properties of a group describe the possible values
+     * that can be read out of that property in actual JS objects. In native
+     * objects, property types account for plain data properties (those with a
+     * slot and no getter or setter hook) and dense elements. In typed objects
+     * and unboxed objects, property types account for object and value
+     * properties and elements in the object, and expando properties in unboxed
+     * objects.
+     *
+     * For accesses on these properties, the correspondence is as follows:
+     *
+     * 1. If the group has unknownProperties(), the possible properties and
+     *    value types for associated JSObjects are unknown.
+     *
+     * 2. Otherwise, for any |obj| in |group|, and any |id| which is a property
+     *    in |obj|, before obj->getProperty(id) the property in |group| for
+     *    |id| must reflect the result of the getProperty.
+     *
+     * There are several exceptions to this:
+     *
+     * 1. For properties of global JS objects which are undefined at the point
+     *    where the property was (lazily) generated, the property type set will
+     *    remain empty, and the 'undefined' type will only be added after a
+     *    subsequent assignment or deletion. After these properties have been
+     *    assigned a defined value, the only way they can become undefined
+     *    again is after such an assign or deletion.
+     *
+     * 2. Array lengths are special cased by the compiler and VM and are not
+     *    reflected in property types.
+     *
+     * 3. In typed objects (but not unboxed objects), the initial values of
+     *    properties (null pointers and undefined values) are not reflected in
+     *    the property types. These values are always possible when reading the
+     *    property.
+     *
+     * We establish these by using write barriers on calls to setProperty and
+     * defineProperty which are on native properties, and on any jitcode which
+     * might update the property with a new type.
+     */
+    Property** propertySet = nullptr;
+
+    // END OF PROPERTIES
+
+  private:
+    static inline uint32_t offsetOfClasp() {
+        return offsetof(ObjectGroup, clasp_);
+    }
+
+    static inline uint32_t offsetOfProto() {
+        return offsetof(ObjectGroup, proto_);
+    }
+
+    static inline uint32_t offsetOfRealm() {
+        return offsetof(ObjectGroup, realm_);
+    }
+
+    static inline uint32_t offsetOfFlags() {
+        return offsetof(ObjectGroup, flags_);
+    }
+
+    static inline uint32_t offsetOfAddendum() {
+        return offsetof(ObjectGroup, addendum_);
+    }
+
     friend class gc::GCRuntime;
     friend class gc::GCTrace;
 
-    /* Class shared by objects in this group. */
-    const Class* clasp_;
-
-    /* Prototype shared by objects in this group. */
-    GCPtr<TaggedProto> proto_;
-
-    /* Realm shared by objects in this group. */
-    JS::Realm* realm_;
+    // See JSObject::offsetOfGroup() comment.
+    friend class js::jit::MacroAssembler;
 
   public:
     const Class* clasp() const {
         return clasp_;
     }
 
     void setClasp(const Class* clasp) {
         MOZ_ASSERT(JS::StringIsASCII(clasp->name));
@@ -151,20 +231,16 @@ class ObjectGroup : public gc::TenuredCe
         MOZ_ASSERT_IF(res, singleton());
         return res;
     }
 
     JSCompartment* compartment() const { return JS::GetCompartmentForRealm(realm_); }
     JSCompartment* maybeCompartment() const { return compartment(); }
     JS::Realm* realm() const { return realm_; }
 
-  private:
-    /* Flags for this group. */
-    ObjectGroupFlags flags_;
-
   public:
     // Kinds of addendums which can be attached to ObjectGroups.
     enum AddendumKind {
         Addendum_None,
 
         // When used by interpreted function, the addendum stores the
         // canonical JSFunction object.
         Addendum_InterpretedFunction,
@@ -186,20 +262,16 @@ class ObjectGroup : public gc::TenuredCe
         // objects, the addendum points to that unboxed group.
         Addendum_OriginalUnboxedGroup,
 
         // When used by typed objects, the addendum stores a TypeDescr.
         Addendum_TypeDescr
     };
 
   private:
-    // If non-null, holds additional information about this object, whose
-    // format is indicated by the object's addendum kind.
-    void* addendum_;
-
     void setAddendum(AddendumKind kind, void* addendum, bool writeBarrier = true);
 
     AddendumKind addendumKind() const {
         return (AddendumKind)
             ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT);
     }
 
     TypeNewScript* newScriptDontCheckGeneration() const {
@@ -328,59 +400,16 @@ class ObjectGroup : public gc::TenuredCe
         Property(const Property& o)
           : id(o.id.get()), types(o.types)
         {}
 
         static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
         static jsid getKey(Property* p) { return p->id; }
     };
 
-  private:
-    /*
-     * Properties of this object.
-     *
-     * The type sets in the properties of a group describe the possible values
-     * that can be read out of that property in actual JS objects. In native
-     * objects, property types account for plain data properties (those with a
-     * slot and no getter or setter hook) and dense elements. In typed objects
-     * and unboxed objects, property types account for object and value
-     * properties and elements in the object, and expando properties in unboxed
-     * objects.
-     *
-     * For accesses on these properties, the correspondence is as follows:
-     *
-     * 1. If the group has unknownProperties(), the possible properties and
-     *    value types for associated JSObjects are unknown.
-     *
-     * 2. Otherwise, for any |obj| in |group|, and any |id| which is a property
-     *    in |obj|, before obj->getProperty(id) the property in |group| for
-     *    |id| must reflect the result of the getProperty.
-     *
-     * There are several exceptions to this:
-     *
-     * 1. For properties of global JS objects which are undefined at the point
-     *    where the property was (lazily) generated, the property type set will
-     *    remain empty, and the 'undefined' type will only be added after a
-     *    subsequent assignment or deletion. After these properties have been
-     *    assigned a defined value, the only way they can become undefined
-     *    again is after such an assign or deletion.
-     *
-     * 2. Array lengths are special cased by the compiler and VM and are not
-     *    reflected in property types.
-     *
-     * 3. In typed objects (but not unboxed objects), the initial values of
-     *    properties (null pointers and undefined values) are not reflected in
-     *    the property types. These values are always possible when reading the
-     *    property.
-     *
-     * We establish these by using write barriers on calls to setProperty and
-     * defineProperty which are on native properties, and on any jitcode which
-     * might update the property with a new type.
-     */
-    Property** propertySet;
   public:
 
     inline ObjectGroup(const Class* clasp, TaggedProto proto, JS::Realm* realm,
                        ObjectGroupFlags initialFlags);
 
     inline bool hasAnyFlags(const AutoSweepObjectGroup& sweep, ObjectGroupFlags flags);
     inline bool hasAllFlags(const AutoSweepObjectGroup& sweep, ObjectGroupFlags flags);
 
@@ -459,40 +488,16 @@ class ObjectGroup : public gc::TenuredCe
     }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     void finalize(FreeOp* fop);
 
     static const JS::TraceKind TraceKind = JS::TraceKind::ObjectGroup;
 
-  private:
-    // See JSObject::offsetOfGroup() comment.
-    friend class js::jit::MacroAssembler;
-
-    static inline uint32_t offsetOfClasp() {
-        return offsetof(ObjectGroup, clasp_);
-    }
-
-    static inline uint32_t offsetOfProto() {
-        return offsetof(ObjectGroup, proto_);
-    }
-
-    static inline uint32_t offsetOfRealm() {
-        return offsetof(ObjectGroup, realm_);
-    }
-
-    static inline uint32_t offsetOfAddendum() {
-        return offsetof(ObjectGroup, addendum_);
-    }
-
-    static inline uint32_t offsetOfFlags() {
-        return offsetof(ObjectGroup, flags_);
-    }
-
   public:
     const ObjectGroupFlags* addressOfFlags() const {
         return &flags_;
     }
 
     // Get the bit pattern stored in an object's addendum when it has an
     // original unboxed group.
     static inline int32_t addendumOriginalUnboxedGroupValue() {
@@ -582,25 +587,44 @@ class ObjectGroup : public gc::TenuredCe
 
   private:
     static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key);
 };
 
 // Structure used to manage the groups in a compartment.
 class ObjectGroupCompartment
 {
-    friend class ObjectGroup;
-
+  private:
     class NewTable;
 
+    struct ArrayObjectKey;
+    using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
+                                                    ReadBarrieredObjectGroup,
+                                                    ArrayObjectKey,
+                                                    SystemAllocPolicy>;
+
+    struct PlainObjectKey;
+    struct PlainObjectEntry;
+    struct PlainObjectTableSweepPolicy {
+        static bool needsSweep(PlainObjectKey* key, PlainObjectEntry* entry);
+    };
+    using PlainObjectTable = JS::GCHashMap<PlainObjectKey,
+                                           PlainObjectEntry,
+                                           PlainObjectKey,
+                                           SystemAllocPolicy,
+                                           PlainObjectTableSweepPolicy>;
+
+    class AllocationSiteTable;
+
+  private:
     // Set of default 'new' or lazy groups in the compartment.
-    NewTable* defaultNewTable;
-    NewTable* lazyTable;
+    NewTable* defaultNewTable = nullptr;
+    NewTable* lazyTable = nullptr;
 
-    // Cache for defaultNewGroup. Purged on GC.
+    // This cache is purged on GC.
     class DefaultNewGroupCache
     {
         ObjectGroup* group_;
         JSObject* associated_;
 
       public:
         DefaultNewGroupCache() { purge(); }
 
@@ -609,66 +633,52 @@ class ObjectGroupCompartment
         }
         void put(ObjectGroup* group, JSObject* associated) {
             group_ = group;
             associated_ = associated;
         }
 
         MOZ_ALWAYS_INLINE ObjectGroup* lookup(const Class* clasp, TaggedProto proto,
                                               JSObject* associated);
-    };
-    DefaultNewGroupCache defaultNewGroupCache;
-
-    struct ArrayObjectKey;
-    using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
-                                                    ReadBarrieredObjectGroup,
-                                                    ArrayObjectKey,
-                                                    SystemAllocPolicy>;
-
-    struct PlainObjectKey;
-    struct PlainObjectEntry;
-    struct PlainObjectTableSweepPolicy {
-        static bool needsSweep(PlainObjectKey* key, PlainObjectEntry* entry);
-    };
-    using PlainObjectTable = JS::GCHashMap<PlainObjectKey,
-                                           PlainObjectEntry,
-                                           PlainObjectKey,
-                                           SystemAllocPolicy,
-                                           PlainObjectTableSweepPolicy>;
+    } defaultNewGroupCache = {};
 
     // Tables for managing groups common to the contents of large script
     // singleton objects and JSON objects. These are vanilla ArrayObjects and
     // PlainObjects, so we distinguish the groups of different ones by looking
     // at the types of their properties.
     //
     // All singleton/JSON arrays which have the same prototype, are homogenous
     // and of the same element type will share a group. All singleton/JSON
     // objects which have the same shape and property types will also share a
     // group. We don't try to collate arrays or objects with type mismatches.
-    ArrayObjectTable* arrayObjectTable;
-    PlainObjectTable* plainObjectTable;
-
-    struct AllocationSiteKey;
-    class AllocationSiteTable;
+    ArrayObjectTable* arrayObjectTable = nullptr;
+    PlainObjectTable* plainObjectTable = nullptr;
 
     // Table for referencing types of objects keyed to an allocation site.
-    AllocationSiteTable* allocationSiteTable;
+    AllocationSiteTable* allocationSiteTable = nullptr;
 
     // A single per-compartment ObjectGroup for all calls to StringSplitString.
     // StringSplitString is always called from self-hosted code, and conceptually
     // the return object for a string.split(string) operation should have a
     // unified type.  Having a global group for this also allows us to remove
     // the hash-table lookup that would be required if we allocated this group
     // on the basis of call-site pc.
-    ReadBarrieredObjectGroup stringSplitStringGroup;
+    ReadBarrieredObjectGroup stringSplitStringGroup = {};
+
+    // END OF PROPERTIES
+
+  private:
+    friend class ObjectGroup;
+
+    struct AllocationSiteKey;
 
   public:
     struct NewEntry;
 
-    ObjectGroupCompartment();
+    ObjectGroupCompartment() = default;
     ~ObjectGroupCompartment();
 
     void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
                                     JSProtoKey kind, ObjectGroup* group);
 
     void removeDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated);
     void replaceDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated,
                                 ObjectGroup* group);
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -175,19 +175,16 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
     stackFormat_(parentRuntime ? js::StackFormat::Default
                                : js::StackFormat::SpiderMonkey),
     wasmInstances(mutexid::WasmRuntimeInstances),
     moduleResolveHook()
 {
     JS_COUNT_CTOR(JSRuntime);
     liveRuntimesCount++;
 
-    /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
-
-    PodZero(&asmJSCacheOps);
     lcovOutput().init();
 }
 
 JSRuntime::~JSRuntime()
 {
     JS_COUNT_DTOR(JSRuntime);
     MOZ_ASSERT(!initialized_);
 
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -8,16 +8,18 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Sprintf.h"
 
+#include <new>
+
 #include "jsapi.h"
 #include "builtin/String.h"
 
 #include "gc/HashUtil.h"
 #include "jit/BaselineJIT.h"
 #include "jit/CompileInfo.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
@@ -867,43 +869,41 @@ TypeSet::IsTypeAboutToBeFinalized(TypeSe
             *v = TypeSet::ObjectType(key);
     } else {
         isAboutToBeFinalized = false;
     }
     return isAboutToBeFinalized;
 }
 
 bool
-TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const
+TypeSet::cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const
 {
-    MOZ_ASSERT(result->empty());
-
     unsigned objectCount = baseObjectCount();
     unsigned capacity = (objectCount >= 2) ? TypeHashSet::Capacity(objectCount) : 0;
 
     ObjectKey** newSet;
     if (capacity) {
         // We allocate an extra word right before the array that stores the
         // capacity, so make sure we clone that as well.
         newSet = alloc->newArray<ObjectKey*>(capacity + 1);
         if (!newSet)
             return false;
         newSet++;
         PodCopy(newSet - 1, objectSet - 1, capacity + 1);
     }
 
-    new(result) TemporaryTypeSet(flags, capacity ? newSet : objectSet);
+    new (result) TemporaryTypeSet(flags, capacity ? newSet : objectSet);
     return true;
 }
 
 TemporaryTypeSet*
 TypeSet::clone(LifoAlloc* alloc) const
 {
-    TemporaryTypeSet* res = alloc->new_<TemporaryTypeSet>();
-    if (!res || !clone(alloc, res))
+    TemporaryTypeSet* res = alloc->pod_malloc<TemporaryTypeSet>();
+    if (!res || !cloneIntoUninitialized(alloc, res))
         return nullptr;
     return res;
 }
 
 TemporaryTypeSet*
 TypeSet::cloneObjectsOnly(LifoAlloc* alloc)
 {
     TemporaryTypeSet* res = clone(alloc);
@@ -1162,20 +1162,19 @@ TypeScript::FreezeTypeSets(CompilerConst
     LifoAlloc* alloc = constraints->alloc();
     AutoSweepTypeScript sweep(script);
     StackTypeSet* existing = script->types(sweep)->typeArray();
 
     size_t count = NumTypeSets(script);
     TemporaryTypeSet* types = alloc->newArrayUninitialized<TemporaryTypeSet>(count);
     if (!types)
         return false;
-    PodZero(types, count);
 
     for (size_t i = 0; i < count; i++) {
-        if (!existing[i].clone(alloc, &types[i]))
+        if (!existing[i].cloneIntoUninitialized(alloc, &types[i]))
             return false;
     }
 
     *pThisTypes = types + (ThisTypes(script) - existing);
     *pArgTypes = (script->functionNonDelazifying() && script->functionNonDelazifying()->nargs())
                  ? (types + (ArgTypes(script, 0) - existing))
                  : nullptr;
     *pBytecodeTypes = types;
@@ -4542,32 +4541,32 @@ JSScript::sweepTypes(const js::AutoSweep
         !hasBaselineScript() &&
         !hasIonScript())
     {
         types_->destroy();
         types_ = nullptr;
 
         // Freeze constraints on stack type sets need to be regenerated the
         // next time the script is analyzed.
-        hasFreezeConstraints_ = false;
+        bitFields_.hasFreezeConstraints_ = false;
 
         return;
     }
 
     unsigned num = TypeScript::NumTypeSets(this);
     StackTypeSet* typeArray = types_->typeArray();
 
     // Remove constraints and references to dead objects from stack type sets.
     for (unsigned i = 0; i < num; i++)
         typeArray[i].sweep(sweep, zone(), *oom);
 
     if (oom->hadOOM()) {
         // It's possible we OOM'd while copying freeze constraints, so they
         // need to be regenerated.
-        hasFreezeConstraints_ = false;
+        bitFields_.hasFreezeConstraints_ = false;
     }
 }
 
 void
 TypeScript::destroy()
 {
     js_delete(this);
 }
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -503,17 +503,20 @@ class TypeSet
 
     bool objectsIntersect(const TypeSet* other) const;
 
     /* Forward all types in this set to the specified constraint. */
     bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint);
 
     // Clone a type set into an arbitrary allocator.
     TemporaryTypeSet* clone(LifoAlloc* alloc) const;
-    bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const;
+
+    // |*result| is not even partly initialized when this function is called:
+    // this function placement-new's its contents into existence.
+    bool cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const;
 
     // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
     TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
     // Create a new TemporaryTypeSet where the type has been set to object.
     TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc);
     TemporaryTypeSet* cloneWithoutObjects(LifoAlloc* alloc);
 
     JSCompartment* maybeCompartment();
--- a/js/src/vm/TypedArrayObject-inl.h
+++ b/js/src/vm/TypedArrayObject-inl.h
@@ -9,17 +9,18 @@
 
 /* Utilities and common inline code for TypedArray */
 
 #include "vm/TypedArrayObject.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/FloatingPoint.h"
-#include "mozilla/PodOperations.h"
+
+#include <algorithm>
 
 #include "jsnum.h"
 
 #include "builtin/Array.h"
 #include "gc/Zone.h"
 #include "jit/AtomicOperations.h"
 #include "js/Conversions.h"
 #include "js/Value.h"
@@ -211,22 +212,34 @@ class UnsharedOps
 
     template<typename T>
     static void memmove(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
         ::memmove(dest.unwrapUnshared(), src.unwrapUnshared(), size);
     }
 
     template<typename T>
     static void podCopy(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
-        mozilla::PodCopy(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
+        // std::copy_n better matches the argument values/types of this
+        // function, but as noted below it allows the input/output ranges to
+        // overlap.  std::copy does not, so use it so the compiler has extra
+        // ability to optimize.
+        const auto* first = src.unwrapUnshared();
+        const auto* last = first + nelem;
+        auto* result = dest.unwrapUnshared();
+        std::copy(first, last, result);
     }
 
     template<typename T>
-    static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
-        mozilla::PodMove(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
+    static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t n) {
+        // std::copy_n copies from |src| to |dest| starting from |src|, so
+        // input/output ranges *may* permissibly overlap, as this function
+        // allows.
+        const auto* start = src.unwrapUnshared();
+        auto* result = dest.unwrapUnshared();
+        std::copy_n(start, n, result);
     }
 
     static SharedMem<void*> extract(TypedArrayObject* obj) {
         return SharedMem<void*>::unshared(obj->viewDataUnshared());
     }
 };
 
 template<typename T, typename Ops>
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -21,16 +21,17 @@
 #include "mozilla/dom/BeforeUnloadEvent.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIFrame.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsSubDocumentFrame.h"
 #include "nsGenericHTMLElement.h"
+#include "nsStubMutationObserver.h"
 
 #include "nsILinkHandler.h"
 #include "nsISelectionListener.h"
 #include "mozilla/dom/Selection.h"
 #include "nsContentUtils.h"
 #include "nsLayoutStylesheetCache.h"
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/DocAccessible.h"
@@ -198,16 +199,118 @@ protected:
   /** default destructor
    */
   virtual ~nsDocViewerFocusListener();
 
 private:
     nsDocumentViewer*  mDocViewer;
 };
 
+namespace viewer_detail {
+
+/**
+ * Mutation observer for use until we hand ourselves over to our SHEntry.
+ */
+class BFCachePreventionObserver final : public nsStubMutationObserver
+{
+public:
+  explicit BFCachePreventionObserver(nsIDocument* aDocument)
+    : mDocument(aDocument)
+  {
+  }
+
+  NS_DECL_ISUPPORTS
+
+  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+  NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
+
+  // Stop observing the document.
+  void Disconnect();
+
+private:
+  ~BFCachePreventionObserver() = default;
+
+  // Helper for the work that needs to happen when mutations happen.
+  void MutationHappened();
+
+  nsIDocument* mDocument; // Weak; we get notified if it dies
+};
+
+NS_IMPL_ISUPPORTS(BFCachePreventionObserver, nsIMutationObserver)
+
+void
+BFCachePreventionObserver::CharacterDataChanged(nsIContent* aContent,
+                                                const CharacterDataChangeInfo&)
+{
+  MutationHappened();
+}
+
+void
+BFCachePreventionObserver::AttributeChanged(Element* aElement,
+                                            int32_t aNameSpaceID,
+                                            nsAtom* aAttribute,
+                                            int32_t aModType,
+                                            const nsAttrValue* aOldValue)
+{
+  MutationHappened();
+}
+
+void
+BFCachePreventionObserver::ContentAppended(nsIContent* aFirstNewContent)
+{
+  MutationHappened();
+}
+
+void
+BFCachePreventionObserver::ContentInserted(nsIContent* aChild)
+{
+  MutationHappened();
+}
+
+void
+BFCachePreventionObserver::ContentRemoved(nsIContent* aChild,
+                                          nsIContent* aPreviousSibling)
+{
+  MutationHappened();
+}
+
+void
+BFCachePreventionObserver::NodeWillBeDestroyed(const nsINode* aNode)
+{
+  mDocument = nullptr;
+}
+
+void
+BFCachePreventionObserver::Disconnect()
+{
+  if (mDocument) {
+    mDocument->RemoveMutationObserver(this);
+    // It will no longer tell us when it goes away, so make sure we're
+    // not holding a dangling ref.
+    mDocument = nullptr;
+  }
+}
+
+void
+BFCachePreventionObserver::MutationHappened()
+{
+  MOZ_ASSERT(mDocument,
+             "How can we not have a document but be getting notified for mutations?");
+  mDocument->DisallowBFCaching();
+  Disconnect();
+}
+
+
+} // namespace viewer_detail
+
+using viewer_detail::BFCachePreventionObserver;
 
 //-------------------------------------------------------------
 class nsDocumentViewer final : public nsIContentViewer,
                                public nsIContentViewerEdit,
                                public nsIDocumentViewerPrint
 
 #ifdef NS_PRINTING
                              , public nsIWebBrowserPrint
@@ -335,16 +438,19 @@ protected:
   RefPtr<nsPresContext>  mPresContext;
   nsCOMPtr<nsIPresShell>   mPresShell;
 
   RefPtr<nsDocViewerSelectionListener> mSelectionListener;
   RefPtr<nsDocViewerFocusListener> mFocusListener;
 
   nsCOMPtr<nsIContentViewer> mPreviousViewer;
   nsCOMPtr<nsISHEntry> mSHEntry;
+  // Observer that will prevent bfcaching if it gets notified.  This
+  // is non-null precisely when mSHEntry is non-null.
+  RefPtr<BFCachePreventionObserver> mBFCachePreventionObserver;
 
   nsIWidget* mParentWidget; // purposely won't be ref counted.  May be null
   bool mAttachedToParent; // view is attached to the parent widget
 
   nsIntRect mBounds;
 
   // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
   // presshell only.
@@ -1557,16 +1663,24 @@ nsDocumentViewer::Close(nsISHEntry *aSHE
   // since we transfer the existing global object to the new document
   // that is loaded.  In the future, the global object may become a proxy
   // for an object that can be switched in and out so that we don't need
   // to disable scripts during paint suppression.
 
   if (!mDocument)
     return NS_OK;
 
+  if (mSHEntry) {
+    if (mBFCachePreventionObserver) {
+      mBFCachePreventionObserver->Disconnect();
+    }
+    mBFCachePreventionObserver = new BFCachePreventionObserver(mDocument);
+    mDocument->AddMutationObserver(mBFCachePreventionObserver);
+  }
+
 #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW)
   // Turn scripting back on
   // after PrintPreview had turned it off
   if (GetIsPrintPreview() && mPrintJob) {
     mPrintJob->TurnScriptingOn(true);
   }
 #endif
 
@@ -1659,28 +1773,44 @@ nsDocumentViewer::Destroy()
     if (mPrintJob->CheckBeforeDestroy()) {
       return NS_OK;
     }
   }
   // Dispatch the 'afterprint' event now, if pending:
   mAutoBeforeAndAfterPrint = nullptr;
 #endif
 
+  // We want to make sure to disconnect mBFCachePreventionObserver before we
+  // Sanitize() below.
+  if (mBFCachePreventionObserver) {
+    mBFCachePreventionObserver->Disconnect();
+    mBFCachePreventionObserver = nullptr;
+  }
+
+  if (mSHEntry && mDocument && !mDocument->IsBFCachingAllowed()) {
+    // Just drop the SHEntry now and pretend like we never even tried to bfcache
+    // this viewer.  This should only happen when someone calls
+    // DisallowBFCaching() after CanSavePresentation() already ran.  Ensure that
+    // the SHEntry has no viewer and its state is synced up.  We want to do this
+    // via a stack reference, in case those calls mess with our members.
+    nsCOMPtr<nsISHEntry> shEntry = mSHEntry.forget();
+    shEntry->SetContentViewer(nullptr);
+    shEntry->SyncPresentationState();
+  }
+
   // If we were told to put ourselves into session history instead of destroy
   // the presentation, do that now.
   if (mSHEntry) {
     if (mPresShell)
       mPresShell->Freeze();
 
     // Make sure the presentation isn't torn down by Hide().
     mSHEntry->SetSticky(mIsSticky);
     mIsSticky = true;
 
-    bool savePresentation = mDocument ? mDocument->IsBFCachingAllowed() : true;
-
     // Remove our root view from the view hierarchy.
     if (mPresShell) {
       nsViewManager *vm = mPresShell->GetViewManager();
       if (vm) {
         nsView *rootView = vm->GetRootView();
 
         if (rootView) {
           nsView *rootViewParent = rootView->GetParent();
@@ -1701,22 +1831,19 @@ nsDocumentViewer::Destroy()
       mDocument->Sanitize();
     }
 
     // Reverse ownership. Do this *after* calling sanitize so that sanitize
     // doesn't cause mutations that make the SHEntry drop the presentation
 
     // Grab a reference to mSHEntry before calling into things like
     // SyncPresentationState that might mess with our members.
-    nsCOMPtr<nsISHEntry> shEntry = mSHEntry; // we'll need this below
-    mSHEntry = nullptr;
-
-    if (savePresentation) {
-      shEntry->SetContentViewer(this);
-    }
+    nsCOMPtr<nsISHEntry> shEntry = mSHEntry.forget(); // we'll need this below
+
+    shEntry->SetContentViewer(this);
 
     // Always sync the presentation state.  That way even if someone screws up
     // and shEntry has no window state at this point we'll be ok; we just won't
     // cache ourselves.
     shEntry->SyncPresentationState();
 
     // Shut down accessibility for the document before we start to tear it down.
 #ifdef ACCESSIBILITY
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -579,17 +579,17 @@ nsNumberControlFrame::SpinnerDownButtonI
 }
 
 bool
 nsNumberControlFrame::IsFocused() const
 {
   // Normally this depends on the state of our anonymous text control (which
   // takes focus for us), but in the case that it does not have a frame we will
   // have focus ourself.
-  return mTextField->AsElement()->State().HasState(NS_EVENT_STATE_FOCUS) ||
+  return mTextField->State().HasState(NS_EVENT_STATE_FOCUS) ||
          mContent->AsElement()->State().HasState(NS_EVENT_STATE_FOCUS);
 }
 
 void
 nsNumberControlFrame::HandleFocusEvent(WidgetEvent* aEvent)
 {
   if (aEvent->mOriginalTarget != mTextField) {
     // Move focus to our text field
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -5985,16 +5985,21 @@ nsGridContainerFrame::Reflow(nsPresConte
     bSize = computedBSize;
   }
   bSize = std::max(bSize - consumedBSize, 0);
   auto& bp = gridReflowInput.mBorderPadding;
   LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
                           computedISize, bSize);
 
   if (!prevInFlow) {
+    if (computedBSize == NS_AUTOHEIGHT && stylePos->mRowGap.HasPercent()) {
+      // Re-resolve the row-gap now that we know our intrinsic block-size.
+      gridReflowInput.mRows.mGridGap =
+        nsLayoutUtils::ResolveGapToLength(stylePos->mRowGap, bSize);
+    }
     // Apply 'align/justify-content' to the grid.
     // CalculateTrackSizes did the columns.
     gridReflowInput.mRows.AlignJustifyContent(stylePos, wm, contentArea.Size(wm));
   }
 
   bSize = ReflowChildren(gridReflowInput, contentArea, aDesiredSize, aStatus);
   bSize = std::max(bSize - consumedBSize, 0);
 
--- a/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html
+++ b/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html
@@ -60,26 +60,26 @@ br { clear: both; }
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
 </div>
 </div>
 
 <div class="float">
-<div class="grid" style="width:60px; height:60px; grid-column-gap:12px">
+<div class="grid" style="width:60px; height:60px; gap:12px">
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
 </div>
 </div>
 
 <div class="inline-grid">
-<div class="grid" style="width:60px; height:60px; grid-column-gap:12px; align-self:start; justify-self:start;">
+<div class="grid" style="width:60px; height:60px; gap:12px; align-self:start; justify-self:start;">
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
 </div>
 </div>
 
 <br>
@@ -137,17 +137,17 @@ br { clear: both; }
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
   <span><x></x></span>
 </div>
 </div>
 
 <div class="float" style="margin-top:-50px; width:62px">
-<div class="grid" style="padding-left:186px; height:60px; grid-column-gap:calc(186px * 0.2);">
+<div class="grid" style="padding-left:186px; height:60px; gap:12px calc(186px * 0.2);">
   <span style="margin-left:-186px; width:30px"><x></x></span>
   <span style="margin-left:-186px; width:30px"><x></x></span>
   <span style="margin-left:-186px; width:30px"><x></x></span>
   <span style="margin-left:-186px; width:30px"><x></x></span>
 </div>
 </div>
 
 </body>
--- a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html
+++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html
@@ -78,25 +78,28 @@ x:last-child {
 
 fill,fit {
   float: left;
   height: 400px;
 }
 
 .zero-progress {
   grid-row-gap: calc(10px - 1%);
-  grid-template-rows: [a] 10px repeat(3, [b] 0 [c]) [d];
+  grid-template-rows: [a] 10px repeat(3, [b] calc(4px / 10) [c]) [d];
+  height:40px;
 }
 .w50.zero-progress {
   grid-row-gap: calc(10px - 1%);
   grid-template-rows: [a] 10px repeat(3, [b] 0 [c]) [d];
+  height:50px;
 }
 .mw50.zero-progress {
   grid-row-gap: calc(10px - 1%);
-  grid-template-rows: [a] 10px repeat(4, [b] 0 [c]) [d];
+  grid-template-rows: [a] 10px repeat(4, [b] calc(5px / 10) [c]) [d];
+  height:50px;
 }
 </style>
 </head>
 <body>
 
 <fill>
 
 <div class="grid r1"><x></x><x></x><a></a><b></b><x></x></div>
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -2027,27 +2027,25 @@ nsTreeBodyFrame::PrefillPropertyArray(in
         nsAutoString value;
         mView->GetCellValue(aRowIndex, aCol, value);
         if (value.EqualsLiteral("true"))
           mScratchArray.AppendElement(nsGkAtoms::checked);
       }
     }
 
     // Read special properties from attributes on the column content node
-    if (aCol->mContent->IsElement() &&
-        aCol->mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
-                                                 nsGkAtoms::insertbefore,
-                                                 nsGkAtoms::_true,
-                                                 eCaseMatters))
+    if (aCol->mContent->AttrValueIs(kNameSpaceID_None,
+                                    nsGkAtoms::insertbefore,
+                                    nsGkAtoms::_true,
+                                    eCaseMatters))
       mScratchArray.AppendElement(nsGkAtoms::insertbefore);
-    if (aCol->mContent->IsElement() &&
-        aCol->mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
-                                                 nsGkAtoms::insertafter,
-                                                 nsGkAtoms::_true,
-                                                 eCaseMatters))
+    if (aCol->mContent->AttrValueIs(kNameSpaceID_None,
+                                    nsGkAtoms::insertafter,
+                                    nsGkAtoms::_true,
+                                    eCaseMatters))
       mScratchArray.AppendElement(nsGkAtoms::insertafter);
   }
 }
 
 nsITheme*
 nsTreeBodyFrame::GetTwistyRect(int32_t aRowIndex,
                                nsTreeColumn* aColumn,
                                nsRect& aImageRect,
--- a/layout/xul/tree/nsTreeColumns.cpp
+++ b/layout/xul/tree/nsTreeColumns.cpp
@@ -260,25 +260,25 @@ nsTreeColumn::GetPrevious(nsITreeColumn*
 
 NS_IMETHODIMP
 nsTreeColumn::Invalidate()
 {
   nsIFrame* frame = GetFrame();
   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
   // Fetch the Id.
-  mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
+  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
 
   // If we have an Id, cache the Id as an atom.
   if (!mId.IsEmpty()) {
     mAtom = NS_Atomize(mId);
   }
 
   // Cache our index.
-  nsTreeUtils::GetColumnIndex(mContent->AsElement(), &mIndex);
+  nsTreeUtils::GetColumnIndex(mContent, &mIndex);
 
   const nsStyleVisibility* vis = frame->StyleVisibility();
 
   // Cache our text alignment policy.
   const nsStyleText* textStyle = frame->StyleText();
 
   mTextAlignment = textStyle->mTextAlign;
   // START or END alignment sometimes means RIGHT
@@ -289,59 +289,59 @@ nsTreeColumn::Invalidate()
     mTextAlignment = NS_STYLE_TEXT_ALIGN_RIGHT;
   } else if (mTextAlignment == NS_STYLE_TEXT_ALIGN_START ||
              mTextAlignment == NS_STYLE_TEXT_ALIGN_END) {
     mTextAlignment = NS_STYLE_TEXT_ALIGN_LEFT;
   }
 
   // Figure out if we're the primary column (that has to have indentation
   // and twisties drawn.
-  mIsPrimary = mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
-                                                  nsGkAtoms::primary,
-                                                  nsGkAtoms::_true,
-                                                  eCaseMatters);
+  mIsPrimary = mContent->AttrValueIs(kNameSpaceID_None,
+                                     nsGkAtoms::primary,
+                                     nsGkAtoms::_true,
+                                     eCaseMatters);
 
   // Figure out if we're a cycling column (one that doesn't cause a selection
   // to happen).
   mIsCycler =
-    mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler,
-                                       nsGkAtoms::_true, eCaseMatters);
+    mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler,
+                          nsGkAtoms::_true, eCaseMatters);
 
   mIsEditable =
-    mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
-                                       nsGkAtoms::_true, eCaseMatters);
+    mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
+                          nsGkAtoms::_true, eCaseMatters);
 
   mIsSelectable =
-    !mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
-                                        nsGkAtoms::_false, eCaseMatters);
+    !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
+                           nsGkAtoms::_false, eCaseMatters);
 
   mOverflow =
-    mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
-                                       nsGkAtoms::_true, eCaseMatters);
+    mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
+                          nsGkAtoms::_true, eCaseMatters);
 
   // Figure out our column type. Default type is text.
   mType = nsITreeColumn::TYPE_TEXT;
   static Element::AttrValuesArray typestrings[] =
     {&nsGkAtoms::checkbox, &nsGkAtoms::password,
      nullptr};
-  switch (mContent->AsElement()->FindAttrValueIn(kNameSpaceID_None,
-                                                 nsGkAtoms::type,
-                                                 typestrings,
-                                                 eCaseMatters)) {
+  switch (mContent->FindAttrValueIn(kNameSpaceID_None,
+                                    nsGkAtoms::type,
+                                    typestrings,
+                                    eCaseMatters)) {
     case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break;
     case 1: mType = nsITreeColumn::TYPE_PASSWORD; break;
   }
 
   // Fetch the crop style.
   mCropStyle = 0;
   static Element::AttrValuesArray cropstrings[] =
     {&nsGkAtoms::center, &nsGkAtoms::left, &nsGkAtoms::start, nullptr};
-  switch (mContent->AsElement()->FindAttrValueIn(kNameSpaceID_None,
-                                                 nsGkAtoms::crop, cropstrings,
-                                                 eCaseMatters)) {
+  switch (mContent->FindAttrValueIn(kNameSpaceID_None,
+                                    nsGkAtoms::crop, cropstrings,
+                                    eCaseMatters)) {
     case 0:
       mCropStyle = 1;
       break;
     case 1:
     case 2:
       mCropStyle = 2;
       break;
   }
@@ -530,21 +530,20 @@ nsTreeColumns::GetKeyColumn()
 
   nsTreeColumn* first = nullptr;
   nsTreeColumn* primary = nullptr;
   nsTreeColumn* sorted = nullptr;
 
   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
     // Skip hidden columns.
     if (!currCol->mContent ||
-        !currCol->mContent->IsElement() ||
-        currCol->mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
-                                                    nsGkAtoms::hidden,
-                                                    nsGkAtoms::_true,
-                                                    eCaseMatters))
+        currCol->mContent->AttrValueIs(kNameSpaceID_None,
+                                       nsGkAtoms::hidden,
+                                       nsGkAtoms::_true,
+                                       eCaseMatters))
       continue;
 
     // Skip non-text column
     if (currCol->GetType() != nsITreeColumn::TYPE_TEXT)
       continue;
 
     if (!first)
       first = currCol;
--- a/mfbt/BufferList.h
+++ b/mfbt/BufferList.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_BufferList_h
 #define mozilla_BufferList_h
 
 #include <algorithm>
 #include "mozilla/AllocPolicy.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Types.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Vector.h"
 #include <string.h>
 
@@ -533,70 +534,110 @@ template<typename AllocPolicy>
 BufferList<AllocPolicy>
 BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
 {
   MOZ_RELEASE_ASSERT(aSize);
   MOZ_RELEASE_ASSERT(mOwning);
   MOZ_ASSERT(aSize % kSegmentAlignment == 0);
   MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0);
 
-  IterImpl iter = aIter;
-  size_t size = aSize;
-  size_t toCopy = std::min(size, aIter.RemainingInSegment());
-  MOZ_ASSERT(toCopy % kSegmentAlignment == 0);
-
-  BufferList result(0, toCopy, mStandardCapacity);
-  BufferList error(0, 0, mStandardCapacity);
-
-  // Copy the head
-  if (!result.WriteBytes(aIter.mData, toCopy)) {
+  auto failure = [this, aSuccess]() {
     *aSuccess = false;
-    return error;
-  }
-  iter.Advance(*this, toCopy);
-  size -= toCopy;
+    return BufferList(0, 0, mStandardCapacity);
+  };
 
-  // Move segments to result
-  auto resultGuard = MakeScopeExit([&] {
-    *aSuccess = false;
-    result.mSegments.erase(result.mSegments.begin()+1, result.mSegments.end());
-  });
+  // Number of segments we'll need to copy data from to satisfy the request.
+  size_t segmentsNeeded = 0;
+  // If this is None then the last segment is a full segment, otherwise we need
+  // to copy this many bytes.
+  Maybe<size_t> lastSegmentSize;
+  {
+    // Copy of the iterator to walk the BufferList and see how many segments we
+    // need to copy.
+    IterImpl iter = aIter;
+    size_t remaining = aSize;
+    while (!iter.Done() && remaining &&
+           remaining >= iter.RemainingInSegment()) {
+      remaining -= iter.RemainingInSegment();
+      iter.Advance(*this, iter.RemainingInSegment());
+      segmentsNeeded++;
+    }
 
-  size_t movedSize = 0;
-  uintptr_t toRemoveStart = iter.mSegment;
-  uintptr_t toRemoveEnd = iter.mSegment;
-  while (!iter.Done() &&
-         !iter.HasRoomFor(size)) {
-    if (!result.mSegments.append(Segment(mSegments[iter.mSegment].mData,
-                                         mSegments[iter.mSegment].mSize,
-                                         mSegments[iter.mSegment].mCapacity))) {
-      return error;
+    if (remaining) {
+      if (iter.Done()) {
+        // We reached the end of the BufferList and there wasn't enough data to
+        // satisfy the request.
+        return failure();
+      }
+      lastSegmentSize.emplace(remaining);
+      // The last block also counts as a segment. This makes the conditionals
+      // on segmentsNeeded work in the rest of the function.
+      segmentsNeeded++;
     }
-    movedSize += iter.RemainingInSegment();
-    size -= iter.RemainingInSegment();
-    toRemoveEnd++;
-    iter.Advance(*this, iter.RemainingInSegment());
+  }
+
+  BufferList result(0, 0, mStandardCapacity);
+  if (!result.mSegments.reserve(segmentsNeeded + lastSegmentSize.isSome())) {
+    return failure();
   }
 
-  if (size)  {
-    if (!iter.HasRoomFor(size) ||
-        !result.WriteBytes(iter.Data(), size)) {
-      return error;
+  // Copy the first segment, it's special because we can't just steal the
+  // entire Segment struct from this->mSegments.
+  size_t firstSegmentSize = std::min(aSize, aIter.RemainingInSegment());
+  if (!result.WriteBytes(aIter.Data(), firstSegmentSize)) {
+    return failure();
+  }
+  aIter.Advance(*this, firstSegmentSize);
+  segmentsNeeded--;
+
+  // The entirety of the request wasn't in the first segment, now copy the
+  // rest.
+  if (segmentsNeeded) {
+    char* finalSegment = nullptr;
+    // Pre-allocate the final segment so that if this fails, we return before
+    // we delete the elements from |this->mSegments|.
+    if (lastSegmentSize.isSome()) {
+      MOZ_RELEASE_ASSERT(mStandardCapacity >= *lastSegmentSize);
+      finalSegment = this->template pod_malloc<char>(mStandardCapacity);
+      if (!finalSegment) {
+        return failure();
+      }
     }
-    iter.Advance(*this, size);
+
+    size_t copyStart = aIter.mSegment;
+    // Copy segments from this over to the result and remove them from our
+    // storage. Not needed if the only segment we need to copy is the last
+    // partial one.
+    size_t segmentsToCopy = segmentsNeeded - lastSegmentSize.isSome();
+    for (size_t i = 0; i < segmentsToCopy; ++i) {
+      result.mSegments.infallibleAppend(
+        Segment(mSegments[aIter.mSegment].mData,
+                mSegments[aIter.mSegment].mSize,
+                mSegments[aIter.mSegment].mCapacity));
+      aIter.Advance(*this, aIter.RemainingInSegment());
+    }
+    MOZ_RELEASE_ASSERT(aIter.mSegment == copyStart + segmentsToCopy);
+    mSegments.erase(mSegments.begin() + copyStart,
+                    mSegments.begin() + copyStart + segmentsToCopy);
+
+    // Reset the iter's position for what we just deleted.
+    aIter.mSegment -= segmentsToCopy;
+
+    if (lastSegmentSize.isSome()) {
+      // We called reserve() on result.mSegments so infallibleAppend is safe.
+      result.mSegments.infallibleAppend(
+        Segment(finalSegment, 0, mStandardCapacity));
+      bool r = result.WriteBytes(aIter.Data(), *lastSegmentSize);
+      MOZ_RELEASE_ASSERT(r);
+      aIter.Advance(*this, *lastSegmentSize);
+    }
   }
 
-  mSegments.erase(mSegments.begin() + toRemoveStart, mSegments.begin() + toRemoveEnd);
-  mSize -= movedSize;
-  aIter.mSegment = iter.mSegment - (toRemoveEnd - toRemoveStart);
-  aIter.mData = iter.mData;
-  aIter.mDataEnd = iter.mDataEnd;
-  MOZ_ASSERT(aIter.mDataEnd == mSegments[aIter.mSegment].End());
+  mSize -= aSize;
   result.mSize = aSize;
 
-  resultGuard.release();
   *aSuccess = true;
   return result;
 }
 
 } // namespace mozilla
 
 #endif /* mozilla_BufferList_h */
--- a/mfbt/tests/TestBufferList.cpp
+++ b/mfbt/tests/TestBufferList.cpp
@@ -240,17 +240,44 @@ int main(void)
   iter.Advance(bl, kExtractStart);
   bl2 = bl.Extract(iter, kExtractSize, &success);
   MOZ_RELEASE_ASSERT(success);
   MOZ_RELEASE_ASSERT(bl2.Size() == kExtractSize);
 
   BufferList bl3 = bl.Extract(iter, kExtractOverSize, &success);
   MOZ_RELEASE_ASSERT(!success);
 
-  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3 - kExtractSize - kExtractStart));
-  MOZ_RELEASE_ASSERT(iter.Done());
-
   iter = bl2.Iter();
   MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kExtractSize));
   MOZ_RELEASE_ASSERT(iter.Done());
 
+  BufferList bl4(8, 8, 8);
+  bl4.WriteBytes("abcd1234", 8);
+  iter = bl4.Iter();
+  iter.Advance(bl4, 8);
+
+  BufferList bl5 = bl4.Extract(iter, kExtractSize, &success);
+  MOZ_RELEASE_ASSERT(!success);
+
+  BufferList bl6(0, 0, 16);
+  bl6.WriteBytes("abcdefgh12345678", 16);
+  bl6.WriteBytes("ijklmnop87654321", 16);
+  iter = bl6.Iter();
+  iter.Advance(bl6, 8);
+  BufferList bl7 = bl6.Extract(iter, 16, &success);
+  MOZ_RELEASE_ASSERT(success);
+  char data[16];
+  MOZ_RELEASE_ASSERT(bl6.ReadBytes(iter, data, 8));
+  MOZ_RELEASE_ASSERT(memcmp(data, "87654321", 8) == 0);
+  iter = bl7.Iter();
+  MOZ_RELEASE_ASSERT(bl7.ReadBytes(iter, data, 16));
+  MOZ_RELEASE_ASSERT(memcmp(data, "12345678ijklmnop", 16) == 0);
+
+  BufferList bl8(0, 0, 16);
+  bl8.WriteBytes("abcdefgh12345678", 16);
+  iter = bl8.Iter();
+  BufferList bl9 = bl8.Extract(iter, 8, &success);
+  MOZ_RELEASE_ASSERT(success);
+  MOZ_RELEASE_ASSERT(bl9.Size() == 8);
+  MOZ_RELEASE_ASSERT(!iter.Done());
+
   return 0;
 }
--- a/python/mozbuild/mozbuild/action/langpack_manifest.py
+++ b/python/mozbuild/mozbuild/action/langpack_manifest.py
@@ -19,16 +19,17 @@ import datetime
 import requests
 import mozversioncontrol
 import mozpack.path as mozpath
 from mozpack.chrome.manifest import (
     Manifest,
     ManifestLocale,
     parse_manifest,
 )
+from mozbuild.configure.util import Version
 from mozbuild.preprocessor import Preprocessor
 import buildconfig
 
 
 def write_file(path, content):
     with io.open(path, 'w', encoding='utf-8') as out:
         out.write(content + '\n')
 
@@ -456,19 +457,30 @@ def main(args):
     args = parser.parse_args(args)
 
     chrome_entries = []
     parse_chrome_manifest(
         os.path.join(args.input, 'chrome.manifest'), args.input, chrome_entries)
 
     defines = parse_defines(args.defines)
 
+    min_app_version = args.min_app_ver
+    if 'a' not in min_app_version:  # Don't mangle alpha versions
+        v = Version(min_app_version)
+        if args.app_name == "SeaMonkey":
+            # SeaMonkey is odd in that <major> hasn't changed for many years.
+            # So min is <major>.<minor>.0
+            min_app_version = "{}.{}.0".format(v.major, v.minor)
+        else:
+            # Language packs should be minversion of {major}.0
+            min_app_version = "{}.0".format(v.major)
+
     res = create_webmanifest(
         args.locales,
-        args.min_app_ver,
+        min_app_version,
         args.max_app_ver,
         args.app_name,
         args.l10n_basedir,
         args.langpack_eid,
         defines,
         chrome_entries
     )
     write_file(os.path.join(args.input, 'manifest.json'), res)
--- a/taskcluster/scripts/builder/build-l10n.sh
+++ b/taskcluster/scripts/builder/build-l10n.sh
@@ -92,16 +92,15 @@ if [ -n "$MOZHARNESS_OPTIONS" ]; then
     for option in $MOZHARNESS_OPTIONS; do
         options="$options --$option"
     done
 fi
 
 cd /builds/worker
 
 python2.7 $WORKSPACE/build/src/testing/${MOZHARNESS_SCRIPT} \
-  --disable-mock \
   $actions \
   $options \
   ${config_path_cmds} \
   ${config_cmds} \
   --log-level=debug \
   --scm-level=$MOZ_SCM_LEVEL \
   --work-dir=$WORKSPACE/build \
--- a/testing/mozharness/configs/openh264/android-aarch64.py
+++ b/testing/mozharness/configs/openh264/android-aarch64.py
@@ -23,22 +23,13 @@ config = {
     'exes': {
         'gittool.py': [os.path.join(external_tools_path, 'gittool.py')],
         'python2.7': "/tools/python27/bin/python2.7",
     },
     'dump_syms_binary': 'dump_syms',
     'arch': 'aarch64',
     # https://dxr.mozilla.org/mozilla-central/rev/5322c03f4c8587fe526172d3f87160031faa6d75/mobile/android/config/mozconfigs/android-aarch64/nightly#6
     'min_sdk': 21,
-    'use_mock': True,
-    'mock_target': 'mozilla-centos6-x86_64',
-    'mock_packages': ['make', 'git', 'nasm', 'glibc-devel.i686',
-                      'libstdc++-devel.i686', 'zip', 'yasm',
-                      'mozilla-python27'],
-    'mock_files': [
-        ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-    ],
     'operating_system': 'android',
     'partial_env': {
         'PATH': '%(abs_work_dir)s/android-sdk-linux/tools:%(PATH)s',
     },
 }
--- a/testing/mozharness/configs/openh264/android-arm.py
+++ b/testing/mozharness/configs/openh264/android-arm.py
@@ -23,22 +23,13 @@ config = {
     'exes': {
         'gittool.py': [os.path.join(external_tools_path, 'gittool.py')],
         'python2.7': "/tools/python27/bin/python2.7",
     },
     'dump_syms_binary': 'dump_syms',
     'arch': 'arm',
     # https://dxr.mozilla.org/mozilla-central/rev/5322c03f4c8587fe526172d3f87160031faa6d75/mobile/android/config/mozconfigs/android-api-15/nightly#6
     'min_sdk': 16,
-    'use_mock': True,
-    'mock_target': 'mozilla-centos6-x86_64',
-    'mock_packages': ['make', 'git', 'nasm', 'glibc-devel.i686',
-                      'libstdc++-devel.i686', 'zip', 'yasm',
-                      'mozilla-python27'],
-    'mock_files': [
-        ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-    ],
     'operating_system': 'android',
     'partial_env': {
         'PATH': '%(abs_work_dir)s/android-sdk-linux/tools:%(PATH)s',
     },
 }
--- a/testing/mozharness/configs/openh264/android-x86.py
+++ b/testing/mozharness/configs/openh264/android-x86.py
@@ -24,22 +24,13 @@ config = {
         'gittool.py': [os.path.join(external_tools_path, 'gittool.py')],
         'python2.7': "/tools/python27/bin/python2.7",
     },
     'avoid_avx2': True,
     'dump_syms_binary': 'dump_syms',
     'arch': 'x86',
     # https://dxr.mozilla.org/mozilla-central/rev/5322c03f4c8587fe526172d3f87160031faa6d75/mobile/android/config/mozconfigs/android-x86/nightly#4
     'min_sdk': 16,
-    'use_mock': True,
-    'mock_target': 'mozilla-centos6-x86_64',
-    'mock_packages': ['make', 'git', 'nasm', 'glibc-devel.i686',
-                      'libstdc++-devel.i686', 'zip', 'yasm',
-                      'mozilla-python27'],
-    'mock_files': [
-        ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-    ],
     'operating_system': 'android',
     'partial_env': {
         'PATH': '%(abs_work_dir)s/android-sdk-linux/tools:%(PATH)s',
     },
 }
--- a/testing/mozharness/configs/openh264/linux32.py
+++ b/testing/mozharness/configs/openh264/linux32.py
@@ -11,20 +11,11 @@ config = {
     'tooltool_manifest_file': "linux.manifest",
     'tooltool_cache': "/builds/tooltool_cache",
     'exes': {
         'gittool.py': [os.path.join(external_tools_path, 'gittool.py')],
         'python2.7': "/tools/python27/bin/python2.7",
     },
     'dump_syms_binary': 'dump_syms',
     'arch': 'x86',
-    'use_mock': True,
     'avoid_avx2': True,
-    'mock_target': 'mozilla-centos6-x86_64',
-    'mock_packages': ['make', 'git', 'nasm', 'glibc-devel.i686',
-                      'libstdc++-devel.i686', 'zip', 'yasm',
-                      'mozilla-python27'],
-    'mock_files': [
-        ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-    ],
     'operating_system': 'linux',
 }
--- a/testing/mozharness/configs/openh264/linux64.py
+++ b/testing/mozharness/configs/openh264/linux64.py
@@ -11,20 +11,11 @@ config = {
     'tooltool_manifest_file': "linux.manifest",
     'tooltool_cache': "/builds/tooltool_cache",
     'exes': {
         'gittool.py': [os.path.join(external_tools_path, 'gittool.py')],
         'python2.7': "/tools/python27/bin/python2.7",
     },
     'dump_syms_binary': 'dump_syms',
     'arch': 'x64',
-    'use_mock': True,
     'avoid_avx2': True,
-    'mock_target': 'mozilla-centos6-x86_64',
-    'mock_packages': ['make', 'git', 'nasm', 'glibc-devel.i686',
-                      'libstdc++-devel.i686', 'zip', 'yasm',
-                      'mozilla-python27'],
-    'mock_files': [
-        ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-    ],
     'operating_system': 'linux',
 }
--- a/testing/mozharness/configs/single_locale/ash_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/ash_android-api-16.py
@@ -48,38 +48,9 @@ config = {
         "MOZ_UPDATE_CHANNEL": MOZ_UPDATE_CHANNEL,
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "platform": "android",
 
     # Balrog
     "build_target": "Android_arm-eabi-gcc3",
-
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-    ],
 }
--- a/testing/mozharness/configs/single_locale/jamun_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/jamun_android-api-16.py
@@ -45,38 +45,9 @@ config = {
         "MOZ_UPDATE_CHANNEL": "nightly-jamun",
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "platform": "android",
 
     # Balrog
     "build_target": "Android_arm-eabi-gcc3",
-
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-    ],
 }
--- a/testing/mozharness/configs/single_locale/maple_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/maple_android-api-16.py
@@ -46,38 +46,9 @@ config = {
         "MOZ_UPDATE_CHANNEL": "nightly-maple",
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "platform": "android",
 
     # Balrog
     "build_target": "Android_arm-eabi-gcc3",
-
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-    ],
 }
--- a/testing/mozharness/configs/single_locale/mozilla-aurora_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/mozilla-aurora_android-api-16.py
@@ -52,38 +52,9 @@ config = {
         "MOZ_UPDATE_CHANNEL": MOZ_UPDATE_CHANNEL,
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "platform": "android",
 
     # Balrog
     "build_target": "Android_arm-eabi-gcc3",
-
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-    ],
 }
--- a/testing/mozharness/configs/single_locale/mozilla-beta_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/mozilla-beta_android-api-16.py
@@ -45,39 +45,9 @@ config = {
         "LD_LIBRARY_PATH": "/lib:/tools/gcc-4.7.2-0moz1/lib:/tools/gcc-4.7.2-0moz1/lib64",
         "EN_US_BINARY_URL": os.environ.get("EN_US_BINARY_URL", EN_US_BINARY_URL),
         "MOZ_OBJDIR": OBJDIR,
         "MOZ_UPDATE_CHANNEL": MOZ_UPDATE_CHANNEL,
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "key_alias": "release",
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-        ('/builds/mozilla-fennec-geoloc-api.key', '/builds/mozilla-fennec-geoloc-api.key'),
-        ('/builds/adjust-sdk-beta.token', '/builds/adjust-sdk-beta.token'),
-    ],
 }
--- a/testing/mozharness/configs/single_locale/mozilla-central_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/mozilla-central_android-api-16.py
@@ -52,38 +52,9 @@ config = {
         "MOZ_UPDATE_CHANNEL": MOZ_UPDATE_CHANNEL,
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "platform": "android",
 
     # Balrog
     "build_target": "Android_arm-eabi-gcc3",
-
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-    ],
 }
--- a/testing/mozharness/configs/single_locale/mozilla-release_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/mozilla-release_android-api-16.py
@@ -45,39 +45,9 @@ config = {
         "LD_LIBRARY_PATH": "/lib:/tools/gcc-4.7.2-0moz1/lib:/tools/gcc-4.7.2-0moz1/lib64",
         "EN_US_BINARY_URL": os.environ.get("EN_US_BINARY_URL", EN_US_BINARY_URL),
         "MOZ_OBJDIR": OBJDIR,
         "MOZ_UPDATE_CHANNEL": MOZ_UPDATE_CHANNEL,
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "key_alias": "release",
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-        ('/builds/mozilla-fennec-geoloc-api.key', '/builds/mozilla-fennec-geoloc-api.key'),
-        ('/builds/adjust-sdk.token', '/builds/adjust-sdk.token'),
-    ],
 }
--- a/testing/mozharness/configs/single_locale/try_android-api-16.py
+++ b/testing/mozharness/configs/single_locale/try_android-api-16.py
@@ -49,38 +49,9 @@ config = {
         "MOZ_UPDATE_CHANNEL": "try", # XXX Invalid
     },
     "upload_branch": "%s-android-api-16" % BRANCH,
     "signature_verification_script": "tools/release/signing/verify-android-signature.sh",
     "platform": "android", # XXX Validate
 
     # Balrog
     "build_target": "Android_arm-eabi-gcc3",
-
-    # Mock
-    "mock_target": "mozilla-centos6-x86_64-android",
-    "mock_packages": ['autoconf213', 'python', 'zip', 'mozilla-python27-mercurial', 'git', 'ccache',
-                      'glibc-static', 'libstdc++-static', 'perl-Test-Simple', 'perl-Config-General',
-                      'gtk2-devel', 'libnotify-devel', 'yasm',
-                      'alsa-lib-devel', 'libcurl-devel',
-                      'wireless-tools-devel', 'libX11-devel',
-                      'libXt-devel', 'mesa-libGL-devel',
-                      'gnome-vfs2-devel', 'GConf2-devel', 'wget',
-                      'mpfr',  # required for system compiler
-                      'xorg-x11-font*',  # fonts required for PGO
-                      'imake',  # required for makedepend!?!
-                      'gcc45_0moz3', 'gcc454_0moz1', 'gcc472_0moz1', 'gcc473_0moz1', 'yasm', 'ccache',  # <-- from releng repo
-                      'valgrind', 'dbus-x11',
-                      'pulseaudio-libs-devel',
-                      'gstreamer-devel', 'gstreamer-plugins-base-devel',
-                      'freetype-2.3.11-6.el6_1.8.x86_64',
-                      'freetype-devel-2.3.11-6.el6_1.8.x86_64',
-                      'java-1.7.0-openjdk-devel',
-                      'openssh-clients',
-                      'zlib-devel-1.2.3-27.el6.i686',
-                      ],
-    "mock_files": [
-        ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
-        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
-        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
-        ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
-    ],
 }
deleted file mode 100644
--- a/testing/mozharness/configs/users/sfink/mock.py
+++ /dev/null
@@ -1,3 +0,0 @@
-config = {
-     "mock_target": "mozilla-centos6-x86_64",
-}
--- a/testing/mozharness/docs/mozharness.mozilla.rst
+++ b/testing/mozharness/docs/mozharness.mozilla.rst
@@ -32,24 +32,16 @@ mozharness.mozilla.buildbot module
 mozharness.mozilla.mapper module
 --------------------------------
 
 .. automodule:: mozharness.mozilla.mapper
     :members:
     :undoc-members:
     :show-inheritance:
 
-mozharness.mozilla.mock module
-------------------------------
-
-.. automodule:: mozharness.mozilla.mock
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
 mozharness.mozilla.mozbase module
 ---------------------------------
 
 .. automodule:: mozharness.mozilla.mozbase
     :members:
     :undoc-members:
     :show-inheritance:
 
deleted file mode 100644
--- a/testing/mozharness/mozharness/mozilla/mock.py
+++ /dev/null
@@ -1,251 +0,0 @@
-#!/usr/bin/env python
-# ***** BEGIN LICENSE BLOCK *****
-# 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/.
-# ***** END LICENSE BLOCK *****
-"""Code to integrate with mock
-"""
-
-import os.path
-import hashlib
-import subprocess
-import os
-
-ERROR_MSGS = {
-    'undetermined_buildroot_lock': 'buildroot_lock_path does not exist.\
-Nothing to remove.'
-}
-
-
-
-# MockMixin {{{1
-class MockMixin(object):
-    """Provides methods to setup and interact with mock environments.
-    https://wiki.mozilla.org/ReleaseEngineering/Applications/Mock
-
-    This is dependent on ScriptMixin
-    """
-    done_mock_setup = False
-    mock_enabled = False
-    default_mock_target = None
-
-    def init_mock(self, mock_target):
-        "Initialize mock environment defined by `mock_target`"
-        cmd = ['mock_mozilla', '-r', mock_target, '--init']
-        return super(MockMixin, self).run_command(cmd, halt_on_failure=True,
-                                                  fatal_exit_code=3)
-
-    def install_mock_packages(self, mock_target, packages):
-        "Install `packages` into mock environment `mock_target`"
-        cmd = ['mock_mozilla', '-r', mock_target, '--install'] + packages
-        # TODO: parse output to see if packages actually were installed
-        return super(MockMixin, self).run_command(cmd, halt_on_failure=True,
-                                                  fatal_exit_code=3)
-
-    def delete_mock_files(self, mock_target, files):
-        """Delete files from the mock environment `mock_target`. `files` should
-        be an iterable of 2-tuples: (src, dst). Only the dst component is
-        deleted."""
-        cmd_base = ['mock_mozilla', '-r', mock_target, '--shell']
-        for src, dest in files:
-            cmd = cmd_base + ['rm -rf %s' % dest]
-            super(MockMixin, self).run_command(cmd, halt_on_failure=True,
-                                               fatal_exit_code=3)
-
-    def copy_mock_files(self, mock_target, files):
-        """Copy files into the mock environment `mock_target`. `files` should
-        be an iterable of 2-tuples: (src, dst)"""
-        cmd_base = ['mock_mozilla', '-r', mock_target, '--copyin', '--unpriv']
-        for src, dest in files:
-            cmd = cmd_base + [src, dest]
-            super(MockMixin, self).run_command(cmd, halt_on_failure=True,
-                                               fatal_exit_code=3)
-            super(MockMixin, self).run_command(
-                ['mock_mozilla', '-r', mock_target, '--shell',
-                 'chown -R mock_mozilla %s' % dest],
-                halt_on_failure=True,
-                fatal_exit_code=3)
-
-    def get_mock_target(self):
-        if self.config.get('disable_mock'):
-            return None
-        return self.default_mock_target or self.config.get('mock_target')
-
-    def enable_mock(self):
-        """Wrap self.run_command and self.get_output_from_command to run inside
-        the mock environment given by self.config['mock_target']"""
-        if not self.get_mock_target():
-            return
-        self.mock_enabled = True
-        self.run_command = self.run_command_m
-        self.get_output_from_command = self.get_output_from_command_m
-
-    def disable_mock(self):
-        """Restore self.run_command and self.get_output_from_command to their
-        original versions. This is the opposite of self.enable_mock()"""
-        if not self.get_mock_target():
-            return
-        self.mock_enabled = False
-        self.run_command = super(MockMixin, self).run_command
-        self.get_output_from_command = super(MockMixin, self).get_output_from_command
-
-    def _do_mock_command(self, func, mock_target, command, cwd=None, env=None, **kwargs):
-        """Internal helper for preparing commands to run under mock. Used by
-        run_mock_command and get_mock_output_from_command."""
-        cmd = ['mock_mozilla', '-r', mock_target, '-q']
-        if cwd:
-            cmd += ['--cwd', cwd]
-
-        if not kwargs.get('privileged'):
-            cmd += ['--unpriv']
-        cmd += ['--shell']
-
-        if not isinstance(command, basestring):
-            command = subprocess.list2cmdline(command)
-
-        # XXX - Hack - gets around AB_CD=%(locale)s type arguments
-        command = command.replace("(", "\\(")
-        command = command.replace(")", "\\)")
-
-        if env:
-            env_cmd = ['/usr/bin/env']
-            for key, value in env.items():
-                # $HOME won't work inside the mock chroot
-                if key == 'HOME':
-                    continue
-                value = value.replace(";", "\\;")
-                env_cmd += ['%s=%s' % (key, value)]
-            cmd.append(subprocess.list2cmdline(env_cmd) + " " + command)
-        else:
-            cmd.append(command)
-        return func(cmd, cwd=cwd, **kwargs)
-
-    def run_mock_command(self, mock_target, command, cwd=None, env=None, **kwargs):
-        """Same as ScriptMixin.run_command, except runs command inside mock
-        environment `mock_target`."""
-        return self._do_mock_command(
-            super(MockMixin, self).run_command,
-            mock_target, command, cwd, env, **kwargs)
-
-    def get_mock_output_from_command(self, mock_target, command, cwd=None, env=None, **kwargs):
-        """Same as ScriptMixin.get_output_from_command, except runs command
-        inside mock environment `mock_target`."""
-        return self._do_mock_command(
-            super(MockMixin, self).get_output_from_command,
-            mock_target, command, cwd, env, **kwargs)
-
-    def reset_mock(self, mock_target=None):
-        """rm mock lock and reset"""
-        c = self.config
-        if mock_target is None:
-            if not c.get('mock_target'):
-                self.fatal("Cound not determine: 'mock_target'")
-            mock_target = c.get('mock_target')
-        buildroot_lock_path = os.path.join(c.get('mock_mozilla_dir', ''),
-                                           mock_target,
-                                           'buildroot.lock')
-        self.info("Removing buildroot lock at path if exists:O")
-        self.info(buildroot_lock_path)
-        if not os.path.exists(buildroot_lock_path):
-            self.info(ERROR_MSGS['undetermined_buildroot_lock'])
-        else:
-            rm_lock_cmd = ['rm', '-f', buildroot_lock_path]
-            super(MockMixin, self).run_command(rm_lock_cmd,
-                                               halt_on_failure=True,
-                                               fatal_exit_code=3)
-        cmd = ['mock_mozilla', '-r', mock_target, '--orphanskill']
-        return super(MockMixin, self).run_command(cmd, halt_on_failure=True,
-                                                  fatal_exit_code=3)
-
-    def setup_mock(self, mock_target=None, mock_packages=None, mock_files=None):
-        """Initializes and installs packages, copies files into mock
-        environment given by configuration in self.config.  The mock
-        environment is given by self.config['mock_target'], the list of packges
-        to install given by self.config['mock_packages'], and the list of files
-        to copy in is self.config['mock_files']."""
-        if self.done_mock_setup or self.config.get('disable_mock'):
-            return
-
-        c = self.config
-
-        if mock_target is None:
-            assert 'mock_target' in c
-            t = c['mock_target']
-        else:
-            t = mock_target
-        self.default_mock_target = t
-
-        # Don't re-initialize mock if we're using the same packages as before
-        # Put the cache inside the mock root so that if somebody else resets
-        # the environment, it invalidates the cache
-        mock_root = super(MockMixin, self).get_output_from_command(
-            ['mock_mozilla', '-r', t, '--print-root-path']
-        )
-        package_hash_file = os.path.join(mock_root, "builds/package_list.hash")
-        if os.path.exists(package_hash_file):
-            old_packages_hash = self.read_from_file(package_hash_file)
-            self.info("old package hash: %s" % old_packages_hash)
-        else:
-            self.info("no previous package list found")
-            old_packages_hash = None
-
-        if mock_packages is None:
-            mock_packages = list(c.get('mock_packages'))
-
-        package_list_hash = hashlib.new('sha1')
-        if mock_packages:
-            for p in sorted(mock_packages):
-                package_list_hash.update(p)
-        package_list_hash = package_list_hash.hexdigest()
-
-        did_init = True
-        # This simple hash comparison doesn't take into account depedency
-        # changes. If you really care about dependencies, then they should be
-        # explicitly listed in the package list.
-        if old_packages_hash != package_list_hash:
-            self.init_mock(t)
-        else:
-            self.info("Our list of packages hasn't changed; skipping re-initialization")
-            did_init = False
-
-        # Still try and install packages here since the package version may
-        # have been updated on the server
-        if mock_packages:
-            self.install_mock_packages(t, mock_packages)
-
-        # Save our list of packages
-        self.write_to_file(package_hash_file,
-                           package_list_hash)
-
-        if mock_files is None:
-            mock_files = list(c.get('mock_files'))
-        if mock_files:
-            if not did_init:
-                # mock complains if you try and copy in files that already
-                # exist, so we need to delete them here first
-                self.info("Deleting old mock files")
-                self.delete_mock_files(t, mock_files)
-            self.copy_mock_files(t, mock_files)
-
-        self.done_mock_setup = True
-
-    def run_command_m(self, *args, **kwargs):
-        """Executes self.run_mock_command if we have a mock target set,
-        otherwise executes self.run_command."""
-        mock_target = self.get_mock_target()
-        if mock_target:
-            self.setup_mock()
-            return self.run_mock_command(mock_target, *args, **kwargs)
-        else:
-            return super(MockMixin, self).run_command(*args, **kwargs)
-
-    def get_output_from_command_m(self, *args, **kwargs):
-        """Executes self.get_mock_output_from_command if we have a mock target
-        set, otherwise executes self.get_output_from_command."""
-        mock_target = self.get_mock_target()
-        if mock_target:
-            self.setup_mock()
-            return self.get_mock_output_from_command(mock_target, *args, **kwargs)
-        else:
-            return super(MockMixin, self).get_output_from_command(*args, **kwargs)
deleted file mode 100644
--- a/testing/mozharness/mozharness/mozilla/taskcluster_helper.py
+++ /dev/null
@@ -1,276 +0,0 @@
-"""Taskcluster module. Defines a few helper functions to call into the taskcluster
-   client.
-"""
-import os
-from datetime import datetime, timedelta
-from urlparse import urljoin
-from mozharness.base.log import INFO
-
-from mozharness.base.log import LogMixin
-
-
-# Taskcluster {{{1
-class Taskcluster(LogMixin):
-    """
-    Helper functions to report data to Taskcluster
-    """
-    def __init__(self, branch, rank, client_id, access_token, log_obj,
-                 task_id=None):
-        self.rank = rank
-        self.log_obj = log_obj
-
-        # Try builds use a different set of credentials which have access to the
-        # buildbot-try scope.
-        if branch == 'try':
-            self.buildbot = 'buildbot-try'
-        else:
-            self.buildbot = 'buildbot'
-
-        # We can't import taskcluster at the top of the script because it is
-        # part of the virtualenv, so import it now. The virtualenv needs to be
-        # activated before this point by the mozharness script, or else we won't
-        # be able to find this module.
-        import taskcluster
-        taskcluster.config['credentials']['clientId'] = client_id
-        taskcluster.config['credentials']['accessToken'] = access_token
-        self.taskcluster_queue = taskcluster.Queue()
-        self.task_id = task_id or taskcluster.slugId()
-        self.put_file = taskcluster.utils.putFile
-
-    def create_task(self, routes):
-        curdate = datetime.utcnow()
-        self.info("Taskcluster taskId: %s" % self.task_id)
-        self.info("Routes: %s" % routes)
-        task = self.taskcluster_queue.createTask({
-            # The null-provisioner and buildbot worker type don't actually exist.
-            # So this task doesn't actually run - we just need to create the task so
-            # we have something to attach artifacts to.
-            "provisionerId": "null-provisioner",
-            "workerType": self.buildbot,
-            "created": curdate,
-            "deadline": curdate + timedelta(hours=1),
-            "routes": routes,
-            "payload": {
-            },
-            "extra": {
-                "index": {
-                    "rank": self.rank,
-                },
-            },
-            "metadata": {
-                "name": "Buildbot/mozharness S3 uploader",
-                "description": "Upload outputs of buildbot/mozharness builds to S3",
-                "owner": "mshal@mozilla.com",
-                "source": "http://hg.mozilla.org/build/mozharness/",
-            }
-        }, taskId=self.task_id)
-        return task
-
-    def claim_task(self, task):
-        self.taskcluster_queue.claimTask(
-            task['status']['taskId'],
-            task['status']['runs'][-1]['runId'],
-            {
-                "workerGroup": self.buildbot,
-                "workerId": self.buildbot,
-            })
-
-    def get_task(self, task_id):
-        return self.taskcluster_queue.status(task_id)
-
-    @staticmethod
-    def get_mime_type(ext, default='application/octet-stream'):
-        mime_types = {
-            ".asc": "text/plain",
-            ".checksums": "text/plain",
-            ".json": "application/json",
-            ".log": "text/plain",
-            ".tar.bz2": "application/x-gtar",
-            ".txt": "text/plain",
-            ".xpi": "application/x-xpinstall",
-            ".zip": "application/zip",
-        }
-        return mime_types.get(ext, default)
-
-    @property
-    def expiration(self):
-        weeks = 52
-        if self.buildbot == 'buildbot-try':
-            weeks = 3
-        return datetime.utcnow() + timedelta(weeks=weeks)
-
-    def create_artifact(self, task, filename):
-        mime_type = self.get_mime_type(os.path.splitext(filename)[1])
-        content_length = os.path.getsize(filename)
-        self.info("Uploading to S3: filename=%s mimetype=%s length=%s" % (
-            filename, mime_type, content_length))
-        # reclaim the task to avoid "claim-expired" errors
-        self.taskcluster_queue.reclaimTask(
-            task['status']['taskId'], task['status']['runs'][-1]['runId'])
-        artifact = self.taskcluster_queue.createArtifact(
-            task['status']['taskId'],
-            task['status']['runs'][-1]['runId'],
-            'public/build/%s' % os.path.basename(filename),
-            {
-                "storageType": "s3",
-                "expires": self.expiration,
-                "contentType": mime_type,
-            })
-        self.put_file(filename, artifact['putUrl'], mime_type)
-        return self.get_taskcluster_url(filename)
-
-    def create_reference_artifact(self, task, filename, url):
-        mime_type = self.get_mime_type(os.path.splitext(filename)[1])
-        self.info("Create reference artifact: filename=%s mimetype=%s url=%s" %
-                  (filename, mime_type, url))
-        # reclaim the task to avoid "claim-expired" errors
-        self.taskcluster_queue.reclaimTask(
-            task['status']['taskId'], task['status']['runs'][-1]['runId'])
-        self.taskcluster_queue.createArtifact(
-            task['status']['taskId'],
-            task['status']['runs'][-1]['runId'],
-            'public/build/%s' % os.path.basename(filename),
-            {
-                "storageType": "reference",
-                "expires": self.expiration,
-                "contentType": mime_type,
-                "url": url,
-            })
-
-    def report_completed(self, task):
-        task_id = task['status']['taskId']
-        run_id = task['status']['runs'][-1]['runId']
-        self.info("Resolving %s, run %s. Full task:" % (task_id, run_id))
-        self.info(str(task))
-        self.taskcluster_queue.reportCompleted(task_id, run_id)
-
-    def report_failed(self, task):
-        task_id = task['status']['taskId']
-        run_id = task['status']['runs'][-1]['runId']
-        self.info("Resolving %s as failed, run %s. Full task:" %
-                  (task_id, run_id))
-        self.info(str(task))
-        self.taskcluster_queue.reportFailed(task_id, run_id)
-
-    def get_taskcluster_url(self, filename):
-        return 'https://queue.taskcluster.net/v1/task/%s/artifacts/public/build/%s' % (
-            self.task_id,
-            os.path.basename(filename)
-        )
-
-
-# TasckClusterArtifactFinderMixin {{{1
-class TaskClusterArtifactFinderMixin(object):
-    # This class depends that you have extended from the base script
-    QUEUE_URL = 'https://queue.taskcluster.net/v1/task/'
-
-    def get_task(self, task_id):
-        """ Get Task Definition """
-        # Signature: task(taskId) : result
-        return self.load_json_url(urljoin(self.QUEUE_URL, task_id))
-
-    def get_list_latest_artifacts(self, task_id):
-        """ Get Artifacts from Latest Run """
-        # Signature: listLatestArtifacts(taskId) : result
-
-        # Notice that this grabs the most recent run of a task since we don't
-        # know the run_id. This slightly slower, however, it is more convenient
-        return self.load_json_url(urljoin(self.QUEUE_URL, '{}/artifacts'.format(task_id)))
-
-    def url_to_artifact(self, task_id, full_path):
-        """ Return a URL for an artifact. """
-        return urljoin(self.QUEUE_URL, '{}/artifacts/{}'.format(task_id, full_path))
-
-    def find_parent_task_id(self, task_id):
-        """ Returns the task_id of the parent task associated to the given task_id."""
-        # Find group id to associated to all related tasks
-        task = self.load_json_url(urljoin(self.QUEUE_URL, task_id))
-        self.log('Task dependencies: {}'.format(' '.join(task['dependencies'])))
-        return task['dependencies'][0]
-
-    def set_bbb_artifacts(self, task_id, properties_file_path):
-        """ Find BBB artifacts through properties_file_path and set them. """
-        p = self.load_json_url(
-            self.url_to_artifact(task_id, properties_file_path))['properties']
-
-        # Set importants artifacts for test jobs
-        self.set_artifacts(
-            p['packageUrl'] if p.get('packageUrl') else None,
-            p['testPackagesUrl'] if p.get('testPackagesUrl') else None,
-            p['symbolsUrl'] if p.get('symbolsUrl') else None
-        )
-
-    def set_artifacts(self, installer, tests, symbols):
-        """ Sets installer, test and symbols URLs from the artifacts of BBB based task."""
-        self.installer_url, self.test_packages_url, self.symbols_url = installer, tests, symbols
-        self.info('Set installer_url: %s' % self.installer_url)
-        self.info('Set test_packages_url: %s' % self.test_packages_url)
-        self.info('Set symbols_url: %s' % self.symbols_url)
-
-    def set_parent_artifacts(self, child_task_id):
-        """ Find and set installer_url, test_url and symbols_url by querying TaskCluster.
-
-        In Buildbot Bridge's normal behaviour we can find the artifacts by inspecting
-        a child's taskId, determine the task in which it depends on and find the uploaded
-        artifacts.
-
-        In order to support multi-tiered task graph scheduling for BBB triggered tasks,
-        we remove the assumption that the task which depends on is the one from which we
-        find the artifacts we need. Instead, we can set a parent_task_id which points to the
-        tasks from which to retrieve the artifacts. This decouples task dependency from task
-        from which to grab the artifacts.
-
-        In-tree triggered BBB tasks do not use parent_task_id, once there is efforts to move
-        the scheduling into tree we can make parent_task_id as the only method.
-
-        """
-        # Task definition
-        child_task = self.get_task(child_task_id)
-
-        properties = child_task['payload']['properties']
-
-        # Case A: The parent_task_id is defined (mozci scheduling)
-        # or installer_path is defined (intree scheduling)
-        if any(k in properties for k in ('parent_task_id', 'installer_path')):
-            # parent_task_id is used to point to the task from which to grab artifacts
-            # rather than the one we depend on
-            parent_id = properties.get('parent_task_id', self.find_parent_task_id(child_task_id))
-
-            # Find out where the parent task uploaded the build
-            parent_task = self.get_task(parent_id)
-
-            # in-tree bbb jobs have the installer_path property
-            # otherwise we look for the build path in task locations
-            installer_path = properties.get(
-                'installer_path',
-                parent_task['extra'].get('locations', {}).get('build')
-            )
-
-            # Case 1: The parent task is a pure TC task
-            if installer_path:
-                self.set_artifacts(
-                    self.url_to_artifact(parent_id, installer_path),
-                    self.url_to_artifact(parent_id, 'public/build/target.test_packages.json'),
-                    self.url_to_artifact(parent_id, 'public/build/target.crashreporter-symbols.zip')
-                )
-            else:
-                # Case 2: The parent task has an associated BBB task
-                # graph_props.json is uploaded in buildbase.py
-                self.set_bbb_artifacts(
-                    task_id=parent_id,
-                    properties_file_path='public/build/buildbot_properties.json'
-                )
-        else:
-            # Case B: We need to query who the parent is since 'parent_task_id'
-            # was not defined as a Buildbot property
-            parent_id = self.find_parent_task_id(child_task_id)
-            self.set_bbb_artifacts(
-                task_id=parent_id,
-                properties_file_path='public/build/buildbot_properties.json'
-            )
-
-        # Use the signed installer if it's set
-        if 'signed_installer_url' in properties:
-            signed_installer_url = properties['signed_installer_url']
-            self.info('Overriding installer_url with signed_installer_url: %s' % signed_installer_url)
-            self.installer_url = signed_installer_url
--- a/testing/mozharness/mozharness/mozilla/testing/testbase.py
+++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py
@@ -19,17 +19,16 @@ from mozharness.base.errors import BaseE
 from mozharness.base.log import FATAL, WARNING
 from mozharness.base.python import (
     ResourceMonitoringMixin,
     VirtualenvMixin,
     virtualenv_config_options,
 )
 from mozharness.mozilla.buildbot import BuildbotMixin, TBPL_WARNING
 from mozharness.mozilla.structuredlog import StructuredOutputParser
-from mozharness.mozilla.taskcluster_helper import TaskClusterArtifactFinderMixin
 from mozharness.mozilla.testing.unittest import DesktopUnittestOutputParser
 from mozharness.mozilla.testing.try_tools import TryToolsMixin, try_config_options
 from mozharness.mozilla.testing.verify_tools import VerifyToolsMixin, verify_config_options
 from mozharness.mozilla.tooltool import TooltoolMixin
 
 from mozharness.lib.python.authentication import get_credentials
 
 INSTALLER_SUFFIXES = ('.apk',  # Android
@@ -100,18 +99,17 @@ testing_config_options = [
       }],
 ] + copy.deepcopy(virtualenv_config_options) \
   + copy.deepcopy(try_config_options) \
   + copy.deepcopy(verify_config_options)
 
 
 # TestingMixin {{{1
 class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin,
-                   TaskClusterArtifactFinderMixin, TooltoolMixin, TryToolsMixin,
-                   VerifyToolsMixin):
+                   TooltoolMixin, TryToolsMixin, VerifyToolsMixin):
     """
     The steps to identify + download the proper bits for [browser] unit
     tests and Talos.
     """
 
     installer_url = None
     installer_path = None
     binary_path = None
--- a/testing/mozharness/mozharness/mozilla/tooltool.py
+++ b/testing/mozharness/mozharness/mozilla/tooltool.py
@@ -87,28 +87,21 @@ class TooltoolMixin(object):
             cmd.extend(['fetch', '-m', manifest, '-o'])
 
         if cache:
             cmd.extend(['--cache-dir' if self.topsrcdir else '-c', cache])
 
         toolchains = os.environ.get('MOZ_TOOLCHAINS')
         if toolchains:
             cmd.extend(toolchains.split())
-        # when mock is enabled run tooltool in mock. We can't use
-        # run_command_m in all cases because it won't exist unless
-        # MockMixin is used on the parent class
-        if self.config.get('mock_target'):
-            cmd_runner = self.run_command_m
-        else:
-            cmd_runner = self.run_command
 
         timeout = self.config.get('tooltool_timeout', 10 * 60)
 
         self.retry(
-            cmd_runner,
+            self.run_command,
             args=(cmd, ),
             kwargs={'cwd': output_dir,
                     'error_list': TooltoolErrorList,
                     'privileged': privileged,
                     'output_timeout': timeout,
                     },
             good_statuses=(0, ),
             error_message="Tooltool %s fetch failed!" % manifest,
--- a/testing/mozharness/mozharness/mozilla/updates/balrog.py
+++ b/testing/mozharness/mozharness/mozilla/updates/balrog.py
@@ -3,22 +3,17 @@ import sys
 
 from mozharness.base.log import INFO
 
 
 # BalrogMixin {{{1
 class BalrogMixin(object):
 
     def query_python(self):
-        python = sys.executable
-        # A mock environment is a special case, the system python isn't
-        # available there
-        if 'mock_target' in self.config:
-            python = 'python2.7'
-        return python
+        return sys.executable
 
     def generate_balrog_props(self, props_path):
         balrog_props = {}
         balrog_props.update(self.buildbot_properties)
 
         balrog_props['hashType'] = self.config.get("hash_type", "sha512")
         if self.config.get('stage_platform'):
             balrog_props['stage_platform'] = self.config['stage_platform']
--- a/testing/mozharness/scripts/desktop_l10n.py
+++ b/testing/mozharness/scripts/desktop_l10n.py
@@ -145,21 +145,16 @@ class DesktopSingleLocale(LocalesMixin, 
          "help": "Specify the total number of chunks of locales"}
     ], [
         ['--en-us-installer-url', ],
         {"action": "store",
          "dest": "en_us_installer_url",
          "type": "string",
          "help": "Specify the url of the en-us binary"}
     ], [
-        ["--disable-mock"], {
-         "dest": "disable_mock",
-         "action": "store_true",
-         "help": "(deprecated) no-op for CLI compatability with mobile_l10n.py"}
-    ], [
         ['--scm-level'], {  # Ignored on desktop for now: see Bug 1414678.
          "action": "store",
          "type": "int",
          "dest": "scm_level",
          "default": 1,
          "help": "This sets the SCM level for the branch being built."
                  " See https://www.mozilla.org/en-US/about/"
                  "governance/policies/commit/access-policy/"}
--- a/testing/mozharness/scripts/mobile_l10n.py
+++ b/testing/mozharness/scripts/mobile_l10n.py
@@ -28,24 +28,23 @@ from mozharness.base.errors import Makef
 from mozharness.base.log import OutputParser
 from mozharness.base.transfer import TransferMixin
 from mozharness.mozilla.buildbot import BuildbotMixin
 from mozharness.mozilla.purge import PurgeMixin
 from mozharness.mozilla.release import ReleaseMixin
 from mozharness.mozilla.tooltool import TooltoolMixin
 from mozharness.base.vcs.vcsbase import MercurialScript
 from mozharness.mozilla.l10n.locales import LocalesMixin
-from mozharness.mozilla.mock import MockMixin
 from mozharness.mozilla.secrets import SecretsMixin
 from mozharness.mozilla.updates.balrog import BalrogMixin
 from mozharness.base.python import VirtualenvMixin
 
 
 # MobileSingleLocale {{{1
-class MobileSingleLocale(MockMixin, LocalesMixin, ReleaseMixin,
+class MobileSingleLocale(LocalesMixin, ReleaseMixin,
                          TransferMixin, TooltoolMixin, BuildbotMixin,
                          PurgeMixin, MercurialScript, BalrogMixin,
                          VirtualenvMixin, SecretsMixin):
     config_options = [[
         ['--locale', ],
         {"action": "extend",
          "dest": "locales",
          "type": "string",
@@ -98,22 +97,16 @@ class MobileSingleLocale(MockMixin, Loca
     ], [
         ['--total-chunks', ],
         {"action": "store",
          "dest": "total_locale_chunks",
          "type": "int",
          "help": "Specify the total number of chunks of locales"
          }
     ], [
-        ["--disable-mock"],
-        {"dest": "disable_mock",
-         "action": "store_true",
-         "help": "do not run under mock despite what gecko-config says",
-         }
-    ], [
         ['--revision', ],
         {"action": "store",
          "dest": "revision",
          "type": "string",
          "help": "Override the gecko revision to use (otherwise use buildbot supplied"
                  " value, or en-US revision) "}
     ], [
         ['--scm-level'],
@@ -500,26 +493,22 @@ class MobileSingleLocale(MockMixin, Loca
         base_package_name = self.query_base_package_name()
         base_package_dir = os.path.join(dirs['abs_objdir'], 'dist')
         repack_env = self.query_repack_env()
         success_count = total_count = 0
         for locale in locales:
             total_count += 1
             signed_path = os.path.join(base_package_dir,
                                        base_package_name % {'locale': locale})
-            # We need to wrap what this function does with mock, since
-            # MobileSigningMixin doesn't know about mock
-            self.enable_mock()
             status = self.verify_android_signature(
                 signed_path,
                 script=c['signature_verification_script'],
                 env=repack_env,
                 key_alias=c['key_alias'],
             )
-            self.disable_mock()
             if status:
                 self.add_failure(locale, message="Errors verifying %s binary!" % locale)
                 # No need to rm because upload is per-locale
                 continue
             success_count += 1
         self.summarize_success_count(success_count, total_count,
                                      message="Validated signatures on %d of %d "
                                              "binaries successfully.")
--- a/testing/mozharness/scripts/openh264_build.py
+++ b/testing/mozharness/scripts/openh264_build.py
@@ -12,27 +12,26 @@ import re
 # load modules from parent dir
 sys.path.insert(1, os.path.dirname(sys.path[0]))
 
 # import the guts
 import mozharness
 from mozharness.base.vcs.vcsbase import VCSScript
 from mozharness.base.log import ERROR
 from mozharness.base.transfer import TransferMixin
-from mozharness.mozilla.mock import MockMixin
 from mozharness.mozilla.tooltool import TooltoolMixin
 
 
 external_tools_path = os.path.join(
     os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))),
     'external_tools',
 )
 
 
-class OpenH264Build(MockMixin, TransferMixin, VCSScript, TooltoolMixin):
+class OpenH264Build(TransferMixin, VCSScript, TooltoolMixin):
     all_actions = [
         'clobber',
         'get-tooltool',
         'checkout-sources',
         'build',
         'test',
         'package',
         'dump-symbols',
@@ -68,22 +67,16 @@ class OpenH264Build(MockMixin, TransferM
         [["--arch"], {
             "dest": "arch",
             "help": "Arch type to use (x64, x86, arm, or aarch64)",
         }],
         [["--os"], {
             "dest": "operating_system",
             "help": "Specify the operating system to build for",
         }],
-        [["--use-mock"], {
-            "dest": "use_mock",
-            "help": "use mock to set up build environment",
-            "action": "store_true",
-            "default": False,
-        }],
         [["--use-yasm"], {
             "dest": "use_yasm",
             "help": "use yasm instead of nasm",
             "action": "store_true",
             "default": False,
         }],
         [["--avoid-avx2"], {
             "dest": "avoid_avx2",
@@ -112,20 +105,16 @@ class OpenH264Build(MockMixin, TransferM
             self,
             config_options=self.config_options,
             require_config_file=require_config_file,
             config=default_config,
             all_actions=all_actions,
             default_actions=default_actions,
         )
 
-        if self.config['use_mock']:
-            self.setup_mock()
-            self.enable_mock()
-
     def get_tooltool(self):
         c = self.config
         if not c.get('tooltool_manifest_file'):
             self.info("Skipping tooltool fetching since no tooltool manifest")
             return
         dirs = self.query_abs_dirs()
         self.mkdir_p(dirs['abs_work_dir'])
         manifest = os.path.join(dirs['base_work_dir'],
@@ -304,35 +293,27 @@ class OpenH264Build(MockMixin, TransferM
             env = self.query_env(self.config['partial_env'])
         kwargs = dict(cwd=repo_dir, env=env)
         dump_syms = os.path.join(dirs['abs_work_dir'], c['dump_syms_binary'])
         self.chmod(dump_syms, 0755)
         python = self.query_exe('python2.7')
         cmd = [python, os.path.join(external_tools_path, 'packagesymbols.py'),
                '--symbol-zip', symbol_zip_path,
                dump_syms, os.path.join(srcdir, package_name)]
-        if self.config['use_mock']:
-            self.disable_mock()
         self.run_command(cmd, **kwargs)
-        if self.config['use_mock']:
-            self.enable_mock()
 
     def upload(self):
-        if self.config['use_mock']:
-            self.disable_mock()
         dirs = self.query_abs_dirs()
         self.scp_upload_directory(
             dirs['abs_upload_dir'],
             self.query_upload_ssh_key(),
             self.query_upload_ssh_user(),
             self.query_upload_ssh_host(),
             self.query_upload_ssh_path(),
         )
-        if self.config['use_mock']:
-            self.enable_mock()
 
     def test(self):
         retval = self.run_make('test')
         if retval != 0:
             self.fatal("test failures")
 
 
 # main {{{1
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -116775,29 +116775,29 @@
      {}
     ]
    ],
    "css/css-grid/alignment/grid-gutters-009.html": [
     [
      "/css/css-grid/alignment/grid-gutters-009.html",
      [
       [
-       "/css/css-grid/reference/grid-collapsed-row-gutters-ref.html",
+       "/css/css-grid/reference/grid-percentage-gap-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
    "css/css-grid/alignment/grid-gutters-010.html": [
     [
      "/css/css-grid/alignment/grid-gutters-010.html",
      [
       [
-       "/css/css-grid/reference/grid-collapsed-row-gutters-ref.html",
+       "/css/css-grid/reference/grid-percentage-gap-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
    "css/css-grid/alignment/grid-gutters-011.html": [
     [
@@ -251059,21 +251059,16 @@
      {}
     ]
    ],
    "css/css-grid/reference/grid-2x2-blue-yellow-lime-magenta.html": [
     [
      {}
     ]
    ],
-   "css/css-grid/reference/grid-collapsed-row-gutters-ref.html": [
-    [
-     {}
-    ]
-   ],
    "css/css-grid/reference/grid-different-gutters-ref.html": [
     [
      {}
     ]
    ],
    "css/css-grid/reference/grid-equal-gutters-ref.html": [
     [
      {}
@@ -251109,16 +251104,21 @@
      {}
     ]
    ],
    "css/css-grid/reference/grid-layout-z-order-ref.html": [
     [
      {}
     ]
    ],
+   "css/css-grid/reference/grid-percentage-gap-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-grid/reference/grid-support-grid-auto-columns-rows-001-ref.html": [
     [
      {}
     ]
    ],
    "css/css-grid/reference/grid-support-grid-auto-columns-rows-002-ref.html": [
     [
      {}
@@ -510032,21 +510032,21 @@
    "f26950ab333903026d8b6d1fe406f051301209d9",
    "reftest"
   ],
   "css/css-grid/alignment/grid-gutters-008.html": [
    "a4a9d7ecc3afb08a561578a25f2933077cacb1cf",
    "reftest"
   ],
   "css/css-grid/alignment/grid-gutters-009.html": [
-   "41a576cd5425e3b60efc328e06941e19c4d49369",
+   "d8fb96e69ca33f25e0d69dec345ca41e0cc68621",
    "reftest"
   ],
   "css/css-grid/alignment/grid-gutters-010.html": [
-   "5ed8d7a44153cd4833f893fe53849a1e63d1a583",
+   "7f54c79f5240a437a217208bf8c547abca49d443",
    "reftest"
   ],
   "css/css-grid/alignment/grid-gutters-011.html": [
    "30bb574c966324ac5377ef8f9250df4f959b9b9f",
    "reftest"
   ],
   "css/css-grid/alignment/grid-gutters-012.html": [
    "a29614ba012488fbcd5cb53694ec483f8548077d",
@@ -511271,20 +511271,16 @@
   "css/css-grid/reference/fr-unit-with-percentage-ref.html": [
    "b708c549640d2f0030e53ba884afb9d40c587049",
    "support"
   ],
   "css/css-grid/reference/grid-2x2-blue-yellow-lime-magenta.html": [
    "a457a82d10d1cc8f2576b6732e68a7854737f63a",
    "support"
   ],
-  "css/css-grid/reference/grid-collapsed-row-gutters-ref.html": [
-   "15a431efb881d37ce24ab376ee3709bd4333bb11",
-   "support"
-  ],
   "css/css-grid/reference/grid-different-gutters-ref.html": [
    "bd1aecfb426cde332794b9657a7d7a905ff1b292",
    "support"
   ],
   "css/css-grid/reference/grid-equal-gutters-ref.html": [
    "9db6eaa6f9569ada08d3c231ec364f4d7e7faf6b",
    "support"
   ],
@@ -511311,16 +511307,20 @@
   "css/css-grid/reference/grid-layout-repeat-notation-ref.html": [
    "f9353d9a20d78eac443725220a6958111c21dc4f",
    "support"
   ],
   "css/css-grid/reference/grid-layout-z-order-ref.html": [
    "3ac4bb610d37d2d31a42e0e6bd86837c9f097b79",
    "support"
   ],
+  "css/css-grid/reference/grid-percentage-gap-ref.html": [
+   "9600489a8f1f24a5fdc9960c84965f4c4ccd7640",
+   "support"
+  ],
   "css/css-grid/reference/grid-support-grid-auto-columns-rows-001-ref.html": [
    "ff487f266aa067949899506059e19d4b8fbf429c",
    "support"
   ],
   "css/css-grid/reference/grid-support-grid-auto-columns-rows-002-ref.html": [
    "15153e77178d8cd869839e9a449e9beb130af023",
    "support"
   ],
--- a/testing/web-platform/meta/custom-elements/CustomElementRegistry.html.ini
+++ b/testing/web-platform/meta/custom-elements/CustomElementRegistry.html.ini
@@ -1,12 +1,13 @@
 [CustomElementRegistry.html]
   prefs: [dom.webcomponents.shadowdom.enabled:true]
   [customElements.define must get callbacks of the constructor prototype]
     expected: FAIL
 
-  [customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present]
+  [customElements.define must rethrow an exception thrown while getting callbacks on the constructor prototype]
     expected: FAIL
 
-  [customElements.define must upgrade elements in the shadow-including tree order]
-    expected:
-      if not stylo: FAIL
+  [customElements.define must rethrow an exception thrown while converting a callback value to Function callback type]
+    expected: FAIL
 
+  [customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present]
+    expected: FAIL
--- a/testing/web-platform/tests/css/css-grid/alignment/grid-gutters-009.html
+++ b/testing/web-platform/tests/css/css-grid/alignment/grid-gutters-009.html
@@ -1,29 +1,36 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Grid Layout Test: Support for percentage values for gap with no defined height for the grid</title>
+<title>CSS Grid Layout Test: Support for percentage values for gap with indefinite percentage basis</title>
 <link rel="help" href="https://www.w3.org/TR/css-grid-1/#gutters">
 <link rel="help" href="https://www.w3.org/TR/css-align-3/#gap-shorthand">
-<link rel="match" href="../reference/grid-collapsed-row-gutters-ref.html">
+<link rel="match" href="../reference/grid-percentage-gap-ref.html">
 <link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk">
 <style>
     #grid {
         display: grid;
         width: 200px;
         gap: 10%;
         grid-template-columns: 90px 90px;
         grid-template-rows: 90px 90px;
         background-color: green;
+        margin-bottom: 30px;
     }
 
     #grid > div {
         background-color: silver;
     }
 </style>
 
-<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should resolve to auto, and therefore collapse to 0 height.</p>
+<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should be percentage of height.</p>
 <div id="grid">
     <div></div>
     <div></div>
     <div></div>
     <div></div>
-</div>
\ No newline at end of file
+</div>
+<div id="grid" style="display:inline-grid; width:auto; gap:calc(20px + 5%)">
+    <div></div>
+    <div></div>
+    <div></div>
+    <div></div>
+</div>
--- a/testing/web-platform/tests/css/css-grid/alignment/grid-gutters-010.html
+++ b/testing/web-platform/tests/css/css-grid/alignment/grid-gutters-010.html
@@ -1,29 +1,36 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Grid Layout Test: Support for percentage values for grid-gap with no defined height for the grid as alias for gap</title>
+<title>CSS Grid Layout Test: Support for percentage values for grid-gap with indefinite percentage basis</title>
 <link rel="help" href="https://www.w3.org/TR/css-grid-1/#gutters">
 <link rel="help" href="https://www.w3.org/TR/css-align-3/#gap-shorthand">
-<link rel="match" href="../reference/grid-collapsed-row-gutters-ref.html">
+<link rel="match" href="../reference/grid-percentage-gap-ref.html">
 <link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk">
 <style>
     #grid {
         display: grid;
         width: 200px;
         grid-gap: 10%;
         grid-template-columns: 90px 90px;
         grid-template-rows: 90px 90px;
         background-color: green;
+        margin-bottom: 30px;
     }
 
     #grid > div {
         background-color: silver;
     }
 </style>
 
-<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should resolve to auto, and therefore collapse to 0 height.</p>
+<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should be percentage of height.</p>
 <div id="grid">
     <div></div>
     <div></div>
     <div></div>
     <div></div>
-</div>
\ No newline at end of file
+</div>
+<div id="grid" style="display:inline-grid; width:auto; grid-gap:calc(20px + 5%)">
+    <div></div>
+    <div></div>
+    <div></div>
+    <div></div>
+</div>
rename from testing/web-platform/tests/css/css-grid/reference/grid-collapsed-row-gutters-ref.html
rename to testing/web-platform/tests/css/css-grid/reference/grid-percentage-gap-ref.html
--- a/testing/web-platform/tests/css/css-grid/reference/grid-collapsed-row-gutters-ref.html
+++ b/testing/web-platform/tests/css/css-grid/reference/grid-percentage-gap-ref.html
@@ -1,47 +1,34 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Grid Layout Reference: a square with a green bar</title>
+<title>CSS Grid Layout Reference: percentage grid gaps</title>
 <link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk" />
 <style>
-    #grid {
+    .grid {
         width:200px;
         height: 180px;
         background-color: green;
         position: relative;
+        margin-bottom: 30px;
     }
 
-    #grid > div {
+    .grid > div {
         background-color: silver;
         width: 90px;
         height: 90px;
         position: absolute;
     }
-
-    #grid :nth-child(1) {
-        top: 0;
-        left: 0;
-    }
-
-    #grid :nth-child(2) {
-        top: 0;
-        left: 110px;
-    }
-
-    #grid :nth-child(3) {
-        top: 90px;
-        left: 0;
-    }
-
-    #grid :nth-child(4) {
-        top: 90px;
-        left: 110px;
-    }
 </style>
 
-<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should resolve to auto, and therefore collapse to 0 height.</p>
-<div id="grid">
-    <div></div>
-    <div></div>
-    <div></div>
-    <div></div>
+<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should be percentage of height.</p>
+<div class="grid">
+    <div style="top:0;     left:0"></div>
+    <div style="top:0;     left:110px"></div>
+    <div style="top:108px; left:0"></div>
+    <div style="top:108px; left:110px"></div>
 </div>
+<div class="grid" style="height:200px">
+    <div style="top:0;     left:0"></div>
+    <div style="top:0;     left:120px"></div>
+    <div style="top:120px; left:0"></div>
+    <div style="top:120px; left:120px"></div>
+</div>
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -694,21 +694,28 @@ var AddonTestUtils = {
   overrideBlocklist(addons) {
     let mock = new MockBlocklist(addons);
     mock.register();
     return mock;
   },
 
   /**
    * Starts up the add-on manager as if it was started by the application.
+   *
+   * @param {string} [newVersion]
+   *        If provided, the application version is changed to this string
+   *        before the AddonManager is started.
    */
-  async promiseStartupManager() {
+  async promiseStartupManager(newVersion) {
     if (this.addonIntegrationService)
       throw new Error("Attempting to startup manager that was already started.");
 
+    if (newVersion)
+      this.appInfo.version = newVersion;
+
     this.addonIntegrationService = Cc["@mozilla.org/addons/integration;1"]
           .getService(Ci.nsIObserver);
 
     this.addonIntegrationService.observe(null, "addons-startup", null);
 
     this.emit("addon-manager-started");
 
     // Load the add-ons list as it was after extension registration
@@ -764,28 +771,20 @@ var AddonTestUtils = {
   /**
    * Asynchronously restart the AddonManager.  If newVersion is provided,
    * simulate an application upgrade (or downgrade) where the version
    * is changed to newVersion when re-started.
    *
    * @param {string} [newVersion]
    *        If provided, the application version is changed to this string
    *        after the AddonManager is shut down, before it is re-started.
-   *
-   * @returns {Promise}
-   *          Resolves when the AddonManager has been re-started.
    */
-  promiseRestartManager(newVersion) {
-    return this.promiseShutdownManager()
-      .then(() => {
-        if (newVersion)
-          this.appInfo.version = newVersion;
-
-        return this.promiseStartupManager(!!newVersion);
-      });
+  async promiseRestartManager(newVersion) {
+    await this.promiseShutdownManager();
+    await this.promiseStartupManager(newVersion);
   },
 
   async loadAddonsList(flush = false) {
     if (flush) {
       let XPIScope = ChromeUtils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
       XPIScope.XPIStates.save();
       await XPIScope.XPIStates._jsonFile._save();
     }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_registry.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_registry.js
@@ -139,25 +139,26 @@ add_task(async function test_4() {
                     "SOFTWARE\\Mozilla\\XPCShell\\Extensions",
                     "addon3@tests.mozilla.org", null);
 
   await promiseRestartManager();
 
   registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
                     "SOFTWARE\\Mozilla\\XPCShell\\Extensions",
                     "addon1@tests.mozilla.org", addon1Dir.path);
-  await promiseRestartManager();
+
+  await promiseShutdownManager();
 
   registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
                     "SOFTWARE\\Mozilla\\XPCShell\\Extensions",
                     "addon1@tests.mozilla.org", null);
   registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
                     "SOFTWARE\\Mozilla\\XPCShell\\Extensions",
                     "addon2@tests.mozilla.org", addon1Dir.path);
   await promiseWriteInstallRDFForExtension(addon2, gProfD, "addon1");
 
-  await promiseRestartManager();
+  await promiseStartupManager();
 
   let [a1, a2, a3] = await AddonManager.getAddonsByIDs(IDS);
   equal(a1, null);
   notEqual(a2, null);
   equal(a3, null);
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_upgrade.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_upgrade.js
@@ -16,19 +16,17 @@ const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 const globalDir = Services.dirsvc.get("XREAddonAppDir", Ci.nsIFile);
 globalDir.append("extensions");
 
 var gGlobalExisted = globalDir.exists();
 var gInstallTime = Date.now();
 
-async function run_test() {
-  do_test_pending();
-
+add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
   // Will be compatible in the first version and incompatible in subsequent versions
   await promiseWriteInstallRDFForExtension({
     id: "addon1@tests.mozilla.org",
     version: "1.0",
     bootstrap: true,
     targetApplications: [{
@@ -80,32 +78,29 @@ async function run_test() {
     targetApplications: [{
       id: "xpcshell@tests.mozilla.org",
       minVersion: "1",
       maxVersion: "1"
     }],
     name: "Test Addon 4",
   }, globalDir);
   setExtensionModifiedTime(dest, gInstallTime);
+});
 
-  run_test_1();
-}
-
-function end_test() {
+registerCleanupFunction(function end_test() {
   if (!gGlobalExisted) {
     globalDir.remove(true);
   } else {
     globalDir.append(do_get_expected_addon_name("addon4@tests.mozilla.org"));
     globalDir.remove(true);
   }
-  executeSoon(do_test_finished);
-}
+});
 
 // Test that the test extensions are all installed
-async function run_test_1() {
+add_task(async function test_1() {
   await promiseStartupManager();
 
   let [a1, a2, a3, a4] = await AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                                             "addon2@tests.mozilla.org",
                                                             "addon3@tests.mozilla.org",
                                                             "addon4@tests.mozilla.org"]);
   Assert.notEqual(a1, null);
   Assert.ok(isExtensionInBootstrappedList(profileDir, a1.id));
@@ -114,59 +109,59 @@ async function run_test_1() {
   Assert.ok(isExtensionInBootstrappedList(profileDir, a2.id));
 
   Assert.notEqual(a3, null);
   Assert.ok(!isExtensionInBootstrappedList(profileDir, a3.id));
 
   Assert.notEqual(a4, null);
   Assert.ok(isExtensionInBootstrappedList(globalDir, a4.id));
   Assert.equal(a4.version, "1.0");
-
-  executeSoon(run_test_2);
-}
+});
 
 // Test that upgrading the application doesn't disable now incompatible add-ons
-async function run_test_2() {
+add_task(async function test_2() {
+  await promiseShutdownManager();
+
   // Upgrade the extension
   var dest = await promiseWriteInstallRDFForExtension({
     id: "addon4@tests.mozilla.org",
     version: "2.0",
     bootstrap: true,
     targetApplications: [{
       id: "xpcshell@tests.mozilla.org",
       minVersion: "2",
       maxVersion: "2"
     }],
     name: "Test Addon 4",
   }, globalDir);
   setExtensionModifiedTime(dest, gInstallTime);
 
-  await promiseRestartManager("2");
+  await promiseStartupManager("2");
   let [a1, a2, a3, a4] = await AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                                             "addon2@tests.mozilla.org",
                                                             "addon3@tests.mozilla.org",
                                                             "addon4@tests.mozilla.org"]);
   Assert.notEqual(a1, null);
   Assert.ok(isExtensionInBootstrappedList(profileDir, a1.id));
 
   Assert.notEqual(a2, null);
   Assert.ok(isExtensionInBootstrappedList(profileDir, a2.id));
 
   Assert.notEqual(a3, null);
   Assert.ok(isExtensionInBootstrappedList(profileDir, a3.id));
 
   Assert.notEqual(a4, null);
   Assert.ok(isExtensionInBootstrappedList(globalDir, a4.id));
   Assert.equal(a4.version, "2.0");
-
-  executeSoon(run_test_3);
-}
+});
 
 // Test that nothing changes when only the build ID changes.
-async function run_test_3() {
+add_task(async function test_3() {
+  await promiseShutdownManager();
+
   // Upgrade the extension
   var dest = await promiseWriteInstallRDFForExtension({
     id: "addon4@tests.mozilla.org",
     version: "3.0",
     bootstrap: true,
     targetApplications: [{
       id: "xpcshell@tests.mozilla.org",
       minVersion: "3",
@@ -174,17 +169,17 @@ async function run_test_3() {
     }],
     name: "Test Addon 4",
   }, globalDir);
   setExtensionModifiedTime(dest, gInstallTime);
 
   // Simulates a simple Build ID change, the platform deletes extensions.ini
   // whenever the application is changed.
   gAddonStartup.remove(true);
-  await promiseRestartManager();
+  await promiseStartupManager();
 
   let [a1, a2, a3, a4] = await AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                                             "addon2@tests.mozilla.org",
                                                             "addon3@tests.mozilla.org",
                                                             "addon4@tests.mozilla.org"]);
   Assert.notEqual(a1, null);
   Assert.ok(isExtensionInBootstrappedList(profileDir, a1.id));
 
@@ -194,11 +189,9 @@ async function run_test_3() {
   Assert.notEqual(a3, null);
   Assert.ok(isExtensionInBootstrappedList(profileDir, a3.id));
 
   Assert.notEqual(a4, null);
   Assert.ok(isExtensionInBootstrappedList(globalDir, a4.id));
   Assert.equal(a4.version, "2.0");
 
   await promiseShutdownManager();
-
-  end_test();
-}
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -180,17 +180,17 @@ skip-if = os == "android"
 [test_provider_shutdown.js]
 [test_provider_unsafe_access_shutdown.js]
 [test_provider_unsafe_access_startup.js]
 [test_proxies.js]
 skip-if = require_signing
 [test_proxy.js]
 [test_registerchrome.js]
 [test_registry.js]
-skip-if = os != 'win' || os == "win"
+skip-if = os != 'win'
 [test_reload.js]
 # Bug 676992: test consistently hangs on Android
 # There's a problem removing a temp file without manually clearing the cache on Windows
 skip-if = os == "android" || os == "win"
 tags = webextensions
 [test_safemode.js]
 [test_schema_change.js]
 [test_seen.js]
@@ -259,17 +259,17 @@ tags = webextensions
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_updatecheck_errors.js]
 [test_updateid.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_upgrade.js]
 # Bug 676992: test consistently hangs on Android
-skip-if = os == "android" || os == "win"
+skip-if = os == "android"
 run-sequentially = Uses global XCurProcD dir.
 [test_upgrade_incompatible.js]
 [test_webextension.js]
 skip-if = appname == "thunderbird"
 tags = webextensions
 [test_webextension_embedded.js]
 skip-if = appname == "thunderbird"
 tags = webextensions
--- a/widget/windows/AudioSession.cpp
+++ b/widget/windows/AudioSession.cpp
@@ -16,16 +16,17 @@
 //#include "AudioSession.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
+#include "mozilla/WindowsVersion.h"
 
 #include <objbase.h>
 
 namespace mozilla {
<