Merge inbound to mozilla-central. a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Thu, 29 Mar 2018 00:55:16 +0300
changeset 410497 6aa3b57955fed5e137d0306478e1a4b424a6d392
parent 410455 c03413e3a8233d7ea0afff73717e1cdeae39fa49 (current diff)
parent 410496 b47ea5c26a80ccc400743e5d9ad57268dcee1636 (diff)
child 410519 c5ab4533710cc2a151495340c712ba66c7acc1ec
child 410556 e51ae123ece9088fbcd1831027a355c5069e427c
push id33729
push userrgurzau@mozilla.com
push dateWed, 28 Mar 2018 21:55:49 +0000
treeherdermozilla-central@6aa3b57955fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
6aa3b57955fe / 61.0a1 / 20180328220110 / files
nightly linux64
6aa3b57955fe / 61.0a1 / 20180328220110 / files
nightly win32
6aa3b57955fe / 61.0a1 / 20180328220110 / files
nightly win64
6aa3b57955fe / 61.0a1 / 20180328220110 / files
nightly mac
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/animation/EffectCompositor.cpp
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/canvas/CanvasRenderingContext2D.cpp
dom/html/HTMLBodyElement.cpp
dom/html/HTMLFontElement.cpp
dom/html/HTMLHRElement.cpp
dom/html/HTMLTableElement.cpp
dom/html/nsGenericHTMLElement.cpp
dom/smil/nsSMILAnimationController.cpp
dom/svg/nsSVGElement.cpp
dom/xbl/nsXBLResourceLoader.cpp
editor/libeditor/HTMLEditor.cpp
layout/base/PresShell.cpp
layout/base/RestyleManager.cpp
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsFrameManager.cpp
layout/base/nsPresContext.cpp
layout/base/nsStyleChangeList.cpp
layout/base/nsStyleChangeList.h
layout/generic/nsFrame.cpp
layout/style/DeclarationBlockInlines.h
layout/style/ErrorReporter.cpp
layout/style/ErrorReporter.h
layout/style/GenericSpecifiedValues.h
layout/style/GenericSpecifiedValuesInlines.h
layout/style/Loader.cpp
layout/style/Loader.h
layout/style/MediaList.h
layout/style/ServoBindings.cpp
layout/style/ServoMediaList.h
layout/style/ServoStyleRule.cpp
layout/style/ServoStyleSheet.cpp
layout/style/ServoUtils.h
layout/style/StreamLoader.cpp
layout/style/StyleSetHandle.h
layout/style/StyleSetHandleInlines.h
layout/style/StyleSheet.cpp
layout/style/nsCSSCounterStyleRule.cpp
layout/style/nsDOMCSSDeclaration.cpp
layout/style/nsHTMLStyleSheet.cpp
layout/style/nsLayoutStylesheetCache.cpp
layout/style/nsLayoutStylesheetCache.h
layout/style/nsStyleStruct.cpp
toolkit/content/XPCNativeWrapper.js
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -46,17 +46,16 @@ var whitelist = [
   // browser/extensions/pdfjs/content/PdfStreamConverter.jsm
   {file: "chrome://pdf.js/locale/chrome.properties"},
   {file: "chrome://pdf.js/locale/viewer.properties"},
 
   // security/manager/pki/resources/content/device_manager.js
   {file: "chrome://pippki/content/load_device.xul"},
 
   // Add-on compat
-  {file: "chrome://global/content/XPCNativeWrapper.js"},
   {file: "chrome://global/locale/brand.dtd"},
 
   // The l10n build system can't package string files only for some platforms.
   // See bug 1339424 for why this is hard to fix.
   {file: "chrome://global/locale/fallbackMenubar.properties",
    platforms: ["linux", "win"]},
   {file: "chrome://global/locale/printPageSetup.dtd", platforms: ["macosx"]},
   {file: "chrome://global/locale/printPreviewProgress.dtd",
--- 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 28.0
+Version 29.0
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-28...release-27
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-28...release-29
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.0
 - babel-preset-react @6.24.1
 - react @16.2.0
 - react-dom @16.2.0
 - webpack @3.11.0
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -1213,16 +1213,17 @@ html[dir="rtl"] .tree-node img.arrow {
   flex: 1;
   overflow-x: auto;
   overflow-y: auto;
 }
 
 .sources-list {
   flex: 1;
   display: flex;
+  overflow: hidden;
 }
 
 .sources-list .tree:focus {
   outline: none;
 }
 
 .sources-list .managed-tree {
   flex: 1;
@@ -3977,16 +3978,20 @@ html .welcomebox .toggle-button-end.coll
 }
 
 .result-list.big li {
   padding: 10px;
   flex-direction: row;
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
+.result-list.small li {
+  justify-content: space-between;
+}
+
 .result-list li:hover {
   background: var(--theme-tab-toolbar-background);
 }
 
 .result-list li.selected {
   background: var(--accordion-header-background);
 }
 
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -5400,25 +5400,27 @@ var _extends = Object.assign || function
 /* eslint complexity: ["error", 30]*/
 
 /**
  * Pause reducer
  * @module reducers/pause
  */
 
 exports.getPauseReason = getPauseReason;
+exports.getPauseCommand = getPauseCommand;
 exports.isStepping = isStepping;
 exports.isPaused = isPaused;
 exports.getPreviousPauseFrameLocation = getPreviousPauseFrameLocation;
 exports.isEvaluatingExpression = isEvaluatingExpression;
 exports.getPopupObjectProperties = getPopupObjectProperties;
 exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
 exports.getShouldPauseOnExceptions = getShouldPauseOnExceptions;
 exports.getShouldIgnoreCaughtExceptions = getShouldIgnoreCaughtExceptions;
 exports.getCanRewind = getCanRewind;
+exports.getExtra = getExtra;
 exports.getFrames = getFrames;
 exports.getGeneratedFrameScope = getGeneratedFrameScope;
 exports.getOriginalFrameScope = getOriginalFrameScope;
 exports.getFrameScopes = getFrameScopes;
 exports.getFrameScope = getFrameScope;
 exports.getSelectedScope = getSelectedScope;
 exports.getSelectedScopeMappings = getSelectedScopeMappings;
 exports.getSelectedFrameId = getSelectedFrameId;
@@ -5430,31 +5432,32 @@ var _reselect = __webpack_require__(993)
 
 var _devtoolsSourceMap = __webpack_require__(1360);
 
 var _prefs = __webpack_require__(226);
 
 var _sources = __webpack_require__(1369);
 
 const createPauseState = exports.createPauseState = () => ({
+  extra: {},
   why: null,
   isWaitingOnBreak: false,
   frames: undefined,
   selectedFrameId: undefined,
   frameScopes: {
     generated: {},
     original: {},
     mappings: {}
   },
   loadedObjects: {},
   shouldPauseOnExceptions: _prefs.prefs.pauseOnExceptions,
   shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions,
   canRewind: false,
   debuggeeUrl: "",
-  command: "",
+  command: null,
   previousLocation: null
 });
 
 const emptyPauseState = {
   pause: null,
   frames: null,
   frameScopes: {
     generated: {},
@@ -5490,26 +5493,27 @@ function update(state = createPauseState
 
     case "MAP_FRAMES":
       {
         return _extends({}, state, { frames: action.frames });
       }
 
     case "ADD_SCOPES":
       {
-        const { frame, status, value } = action;
+        const { frame, extra, status, value } = action;
         const selectedFrameId = frame.id;
 
         const generated = _extends({}, state.frameScopes.generated, {
           [selectedFrameId]: {
             pending: status !== "done",
             scope: value
           }
         });
         return _extends({}, state, {
+          extra: extra,
           frameScopes: _extends({}, state.frameScopes, {
             generated
           })
         });
       }
 
     case "TRAVEL_TO":
       return _extends({}, state, action.data.paused);
@@ -5573,27 +5577,27 @@ function update(state = createPauseState
         shouldIgnoreCaughtExceptions
       });
 
     case "COMMAND":
       {
         return action.status === "start" ? _extends({}, state, emptyPauseState, {
           command: action.command,
           previousLocation: buildPreviousLocation(state, action)
-        }) : _extends({}, state, { command: "" });
+        }) : _extends({}, state, { command: null });
       }
 
     case "RESUME":
       // We clear why on resume because we need it to decide if
       // we shoul re-evaluate watch expressions.
       return _extends({}, state, { why: null });
 
     case "EVALUATE_EXPRESSION":
       return _extends({}, state, {
-        command: action.status === "start" ? "expression" : ""
+        command: action.status === "start" ? "expression" : null
       });
 
     case "NAVIGATE":
       return _extends({}, state, emptyPauseState, { debuggeeUrl: action.url });
   }
 
   return state;
 }
@@ -5630,18 +5634,22 @@ function buildPreviousLocation(state, ac
 const getPauseState = state => state.pause;
 
 const getAllPopupObjectProperties = exports.getAllPopupObjectProperties = (0, _reselect.createSelector)(getPauseState, pauseWrapper => pauseWrapper.loadedObjects);
 
 function getPauseReason(state) {
   return state.pause.why;
 }
 
+function getPauseCommand(state) {
+  return state.pause && state.pause.command;
+}
+
 function isStepping(state) {
-  return ["stepIn", "stepOver", "stepOut"].includes(state.pause.command);
+  return ["stepIn", "stepOver", "stepOut"].includes(getPauseCommand(state));
 }
 
 function isPaused(state) {
   return !!getFrames(state);
 }
 
 function getPreviousPauseFrameLocation(state) {
   return state.pause.previousLocation;
@@ -5666,16 +5674,20 @@ function getShouldPauseOnExceptions(stat
 function getShouldIgnoreCaughtExceptions(state) {
   return state.pause.shouldIgnoreCaughtExceptions;
 }
 
 function getCanRewind(state) {
   return state.pause.canRewind;
 }
 
+function getExtra(state) {
+  return state.pause.extra;
+}
+
 function getFrames(state) {
   return state.pause.frames;
 }
 
 function getGeneratedFrameScope(state, frameId) {
   if (!frameId) {
     return null;
   }
@@ -6383,57 +6395,61 @@ Object.defineProperty(exports, "__esModu
 });
 exports.setSourceMetaData = setSourceMetaData;
 exports.setSymbols = setSymbols;
 exports.setOutOfScopeLocations = setOutOfScopeLocations;
 exports.setPausePoints = setPausePoints;
 
 var _selectors = __webpack_require__(3590);
 
+var _pause = __webpack_require__(1639);
+
 var _setInScopeLines = __webpack_require__(1781);
 
 var _parser = __webpack_require__(1365);
 
 var _promise = __webpack_require__(1653);
 
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-
 function setSourceMetaData(sourceId) {
   return async ({ dispatch, getState }) => {
     const source = (0, _selectors.getSource)(getState(), sourceId);
     if (!source || !source.text || source.isWasm) {
       return;
     }
 
     const framework = await (0, _parser.getFramework)(source.id);
     dispatch({
       type: "SET_SOURCE_METADATA",
       sourceId: source.id,
       sourceMetaData: {
         framework
       }
     });
   };
-}
+} /* This Source Code Form is subject to the terms of the Mozilla Public
+   * License, v. 2.0. If a copy of the MPL was not distributed with this
+   * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 function setSymbols(sourceId) {
   return async ({ dispatch, getState }) => {
     const source = (0, _selectors.getSource)(getState(), sourceId);
     if (!source || !source.text || source.isWasm || (0, _selectors.hasSymbols)(getState(), source)) {
       return;
     }
 
     await dispatch({
       type: "SET_SYMBOLS",
       source: source.toJS(),
       [_promise.PROMISE]: (0, _parser.getSymbols)(source.id)
     });
 
+    if ((0, _selectors.isPaused)(getState())) {
+      await dispatch((0, _pause.mapFrames)());
+    }
+
     await dispatch(setPausePoints(sourceId));
     await dispatch(setSourceMetaData(sourceId));
   };
 }
 
 function setOutOfScopeLocations() {
   return async ({ dispatch, getState }) => {
     const location = (0, _selectors.getSelectedLocation)(getState());
@@ -7707,64 +7723,35 @@ module.exports = {
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.containsPosition = containsPosition;
-exports.findClosestScope = findClosestScope;
 exports.getASTLocation = getASTLocation;
 exports.findScopeByName = findScopeByName;
 
 var _parser = __webpack_require__(1365);
 
-function containsPosition(a, b) {
-  const startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column;
-  const endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column;
-
-  return startsBefore && endsAfter;
-} /* This Source Code Form is subject to the terms of the Mozilla Public
-   * License, v. 2.0. If a copy of the MPL was not distributed with this
-   * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-
-function findClosestScope(functions, location) {
-  return functions.reduce((found, currNode) => {
-    if (currNode.name === "anonymous" || !containsPosition(currNode.location, {
-      line: location.line,
-      column: location.column || 0
-    })) {
-      return found;
-    }
-
-    if (!found) {
-      return currNode;
-    }
-
-    if (found.location.start.line > currNode.location.start.line) {
-      return found;
-    }
-    if (found.location.start.line === currNode.location.start.line && found.location.start.column > currNode.location.start.column) {
-      return found;
-    }
-
-    return currNode;
-  }, null);
-}
+var _ast = __webpack_require__(1638);
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 function getASTLocation(source, symbols, location) {
   if (source.isWasm || !symbols || symbols.loading) {
     return { name: undefined, offset: location };
   }
 
   const functions = [...symbols.functions];
 
-  const scope = findClosestScope(functions, location);
+  const scope = (0, _ast.findClosestFunction)(functions, location);
   if (scope) {
     // we only record the line, but at some point we may
     // also do column offsets
     const line = location.line - scope.location.start.line;
     return {
       name: scope.name,
       offset: { line, column: undefined }
     };
@@ -21925,17 +21912,17 @@ var _reactRedux = __webpack_require__(35
 var _devtoolsContextmenu = __webpack_require__(1413);
 
 var _devtoolsSourceMap = __webpack_require__(1360);
 
 var _clipboard = __webpack_require__(1388);
 
 var _function = __webpack_require__(1597);
 
-var _astBreakpointLocation = __webpack_require__(1416);
+var _ast = __webpack_require__(1638);
 
 var _editor = __webpack_require__(1358);
 
 var _source = __webpack_require__(1356);
 
 var _selectors = __webpack_require__(3590);
 
 var _actions = __webpack_require__(1354);
@@ -22133,18 +22120,18 @@ const {
 
 exports.default = (0, _reactRedux.connect)(state => {
   const selectedSource = (0, _selectors.getSelectedSource)(state);
   return {
     selectedLocation: (0, _selectors.getSelectedLocation)(state),
     selectedSource,
     hasPrettyPrint: !!(0, _selectors.getPrettySource)(state, selectedSource.get("id")),
     contextMenu: (0, _selectors.getContextMenu)(state),
-    getFunctionText: line => (0, _function.findFunctionText)(line, selectedSource.toJS(), (0, _selectors.getSymbols)(state, selectedSource.toJS())),
-    getFunctionLocation: line => (0, _astBreakpointLocation.findClosestScope)((0, _selectors.getSymbols)(state, selectedSource.toJS()).functions, {
+    getFunctionText: line => (0, _function.findFunctionText)(line, selectedSource.toJS(), (0, _selectors.getSymbols)(state, selectedSource)),
+    getFunctionLocation: line => (0, _ast.findClosestFunction)((0, _selectors.getSymbols)(state, selectedSource).functions, {
       line,
       column: Infinity
     })
   };
 }, {
   addExpression,
   evaluateInConsole,
   flashLineRange,
@@ -22162,26 +22149,29 @@ exports.default = (0, _reactRedux.connec
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.findFunctionText = findFunctionText;
 
-var _astBreakpointLocation = __webpack_require__(1416);
+var _ast = __webpack_require__(1638);
 
 var _indentation = __webpack_require__(1438);
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 function findFunctionText(line, source, symbols) {
-  const func = (0, _astBreakpointLocation.findClosestScope)(symbols.functions, { line, column: Infinity });
+  const func = (0, _ast.findClosestFunction)(symbols.functions, {
+    line,
+    column: Infinity
+  });
   if (!func) {
     return null;
   }
 
   const { location: { start, end } } = func;
   const lines = source.text.split("\n");
   const firstLine = lines[start.line - 1].slice(start.column);
   const lastLine = lines[end.line - 1].slice(0, end.column);
@@ -22466,33 +22456,35 @@ var _CommandBar2 = _interopRequireDefaul
 var _UtilsBar = __webpack_require__(1609);
 
 var _UtilsBar2 = _interopRequireDefault(_UtilsBar);
 
 var _BreakpointsDropdown = __webpack_require__(1790);
 
 var _BreakpointsDropdown2 = _interopRequireDefault(_BreakpointsDropdown);
 
+var _FrameworkComponent = __webpack_require__(3623);
+
+var _FrameworkComponent2 = _interopRequireDefault(_FrameworkComponent);
+
 var _ChromeScopes = __webpack_require__(1610);
 
 var _ChromeScopes2 = _interopRequireDefault(_ChromeScopes);
 
 var _Scopes2 = __webpack_require__(1611);
 
 var _Scopes3 = _interopRequireDefault(_Scopes2);
 
 __webpack_require__(1342);
 
 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/>. */
-
-const Scopes = _prefs.features.chromeScopes ? _ChromeScopes2.default : _Scopes3.default;
+const Scopes = _prefs.features.chromeScopes ? _ChromeScopes2.default : _Scopes3.default; /* This Source Code Form is subject to the terms of the Mozilla Public
+                                                                                          * License, v. 2.0. If a copy of the MPL was not distributed with this
+                                                                                          * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 function debugBtn(onClick, type, className, tooltip) {
   return _react2.default.createElement(
     "button",
     {
       onClick: onClick,
       className: `${type} ${className}`,
       key: type,
@@ -22553,16 +22545,30 @@ class SecondaryPanes extends _react.Comp
       component: _react2.default.createElement(Scopes, null),
       opened: _prefs.prefs.scopesVisible,
       onToggle: opened => {
         _prefs.prefs.scopesVisible = opened;
       }
     };
   }
 
+  getComponentItem() {
+    const { extra: { react } } = this.props;
+
+    return {
+      header: react.displayName,
+      className: "component-pane",
+      component: _react2.default.createElement(_FrameworkComponent2.default, null),
+      opened: _prefs.prefs.componentVisible,
+      onToggle: opened => {
+        _prefs.prefs.componentVisible = opened;
+      }
+    };
+  }
+
   getWatchItem() {
     return {
       header: L10N.getStr("watchExpressions.header"),
       className: "watch-expressions-pane",
       buttons: this.watchExpressionHeaderButtons(),
       component: _react2.default.createElement(_Expressions2.default, null),
       opened: _prefs.prefs.expressionsVisible,
       onToggle: opened => {
@@ -22620,32 +22626,37 @@ class SecondaryPanes extends _react.Comp
       shouldIgnoreCaughtExceptions,
       isWaitingOnBreak
     } = this.props;
 
     return (0, _BreakpointsDropdown2.default)(breakOnNext, pauseOnExceptions, shouldPauseOnExceptions, shouldIgnoreCaughtExceptions, isWaitingOnBreak);
   }
 
   getStartItems() {
-    const { workers } = this.props;
+    const { extra, workers } = this.props;
 
     const items = [];
     if (this.props.horizontal) {
       if (_prefs.features.workers && workers.size > 0) {
         items.push(this.getWorkersItem());
       }
 
       items.push(this.getWatchItem());
     }
 
     items.push(this.getBreakpointsItem());
 
     if (this.props.hasFrames) {
       items.push(this.getCallStackItem());
+
       if (this.props.horizontal) {
+        if (extra && extra.react) {
+          items.push(this.getComponentItem());
+        }
+
         items.push(this.getScopeItem());
       }
     }
 
     if (_prefs.features.eventListeners) {
       items.push({
         header: L10N.getStr("eventListenersHeader"),
         className: "event-listeners-pane",
@@ -22656,30 +22667,34 @@ class SecondaryPanes extends _react.Comp
     return items.filter(item => item);
   }
 
   renderHorizontalLayout() {
     return _react2.default.createElement(_Accordion2.default, { items: this.getItems() });
   }
 
   getEndItems() {
-    const { workers } = this.props;
+    const { extra, workers } = this.props;
 
     let items = [];
 
     if (this.props.horizontal) {
       return [];
     }
 
     if (_prefs.features.workers && workers.size > 0) {
       items.push(this.getWorkersItem());
     }
 
     items.push(this.getWatchItem());
 
+    if (extra && extra.react) {
+      items.push(this.getComponentItem());
+    }
+
     if (this.props.hasFrames) {
       items = [...items, this.getScopeItem()];
     }
 
     return items;
   }
 
   getItems() {
@@ -22723,16 +22738,17 @@ class SecondaryPanes extends _react.Comp
   }
 }
 
 SecondaryPanes.contextTypes = {
   shortcuts: _propTypes2.default.object
 };
 
 exports.default = (0, _reactRedux.connect)(state => ({
+  extra: (0, _selectors.getExtra)(state),
   hasFrames: !!(0, _selectors.getTopFrame)(state),
   breakpoints: (0, _selectors.getBreakpoints)(state),
   breakpointsDisabled: (0, _selectors.getBreakpointsDisabled)(state),
   breakpointsLoading: (0, _selectors.getBreakpointsLoading)(state),
   isWaitingOnBreak: (0, _selectors.getIsWaitingOnBreak)(state),
   shouldPauseOnExceptions: (0, _selectors.getShouldPauseOnExceptions)(state),
   shouldIgnoreCaughtExceptions: (0, _selectors.getShouldIgnoreCaughtExceptions)(state),
   workers: (0, _selectors.getWorkers)(state)
@@ -26370,16 +26386,18 @@ function astCommand(stepType) {
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.findBestMatchExpression = findBestMatchExpression;
 exports.findEmptyLines = findEmptyLines;
+exports.containsPosition = containsPosition;
+exports.findClosestFunction = findClosestFunction;
 
 var _lodash = __webpack_require__(2);
 
 function findBestMatchExpression(symbols, tokenPos) {
   const { memberExpressions, identifiers } = symbols;
   const { line, column } = tokenPos;
   return identifiers.concat(memberExpressions).reduce((found, expression) => {
     const overlaps = expression.location.start.line == line && expression.location.start.column <= column && expression.location.end.column >= column && !expression.computed;
@@ -26405,16 +26423,47 @@ function findEmptyLines(selectedSource, 
   if (!selectedSource.text) {
     return [];
   }
   const lineCount = selectedSource.text.split("\n").length;
   const sourceLines = (0, _lodash.range)(1, lineCount + 1);
   return (0, _lodash.without)(sourceLines, ...breakpointLines);
 }
 
+function containsPosition(a, b) {
+  const startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column;
+  const endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column;
+
+  return startsBefore && endsAfter;
+}
+
+function findClosestFunction(functions, location) {
+  return functions.reduce((found, currNode) => {
+    if (currNode.name === "anonymous" || !containsPosition(currNode.location, {
+      line: location.line,
+      column: location.column || 0
+    })) {
+      return found;
+    }
+
+    if (!found) {
+      return currNode;
+    }
+
+    if (found.location.start.line > currNode.location.start.line) {
+      return found;
+    }
+    if (found.location.start.line === currNode.location.start.line && found.location.start.column > currNode.location.start.column) {
+      return found;
+    }
+
+    return currNode;
+  }, null);
+}
+
 /***/ }),
 
 /***/ 1639:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
@@ -27174,17 +27223,20 @@ class QuickOpenModal extends _react.Comp
     };
 
     this.searchSymbols = query => {
       const { symbols: { functions, variables } } = this.props;
 
       let results = functions;
       if (this.isVariableQuery()) {
         results = variables;
-      }
+      } else {
+        results = results.filter(result => result.title !== "anonymous");
+      }
+
       if (query === "@" || query === "#") {
         return this.setState({ results });
       }
 
       this.setState({ results: filter(results, query.slice(1)) });
     };
 
     this.searchShortcuts = query => {
@@ -27590,36 +27642,43 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.fetchScopes = fetchScopes;
 
 var _selectors = __webpack_require__(3590);
 
 var _mapScopes = __webpack_require__(1634);
 
+var _preview = __webpack_require__(1786);
+
 var _promise = __webpack_require__(1653);
 
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
 function fetchScopes() {
   return async function ({ dispatch, getState, client, sourceMaps }) {
     const frame = (0, _selectors.getSelectedFrame)(getState());
     if (!frame || (0, _selectors.getGeneratedFrameScope)(getState(), frame.id)) {
       return;
     }
 
+    const extra = await dispatch((0, _preview.getExtra)("this;", frame.this, frame));
+
     const scopes = dispatch({
       type: "ADD_SCOPES",
       frame,
+      extra,
       [_promise.PROMISE]: client.getFrameScopes(frame)
     });
 
     await dispatch((0, _mapScopes.mapScopes)(scopes, frame));
   };
-} /* 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/>. */
+}
 
 /***/ }),
 
 /***/ 1657:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
@@ -30163,16 +30222,17 @@ function createLocation({
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /* 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/>. */
 
+exports.getExtra = getExtra;
 exports.updatePreview = updatePreview;
 exports.setPreview = setPreview;
 exports.clearPreview = clearPreview;
 
 var _ast = __webpack_require__(1638);
 
 var _editor = __webpack_require__(1358);
 
@@ -30237,16 +30297,24 @@ function isInvalidTarget(target) {
   const invalidToken = tokenText === "" || tokenText.match(/[(){}\|&%,.;=<>\+-/\*\s]/);
 
   // exclude codemirror elements that are not tokens
   const invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0;
 
   return invalidTarget || invalidToken || invaildType;
 }
 
+function getExtra(expression, result, selectedFrame) {
+  return async ({ dispatch, getState, client, sourceMaps }) => {
+    const extra = await getExtraProps(expression, result, expr => client.evaluateInFrame(selectedFrame.id, expr));
+
+    return extra;
+  };
+}
+
 function updatePreview(target, editor) {
   return ({ dispatch, getState, client, sourceMaps }) => {
     const tokenPos = (0, _editor.getTokenLocation)(editor.codeMirror, target);
     const cursorPos = target.getBoundingClientRect();
     const preview = (0, _selectors.getPreview)(getState());
 
     if ((0, _selectors.getCanRewind)(getState())) {
       return;
@@ -30317,17 +30385,17 @@ function setPreview(expression, location
         }
 
         const { result } = await client.evaluateInFrame(selectedFrame.id, expression);
 
         if (result === undefined) {
           return;
         }
 
-        const extra = await getExtraProps(expression, result, expr => client.evaluateInFrame(selectedFrame.id, expr));
+        const extra = await dispatch(getExtra(expression, result, selectedFrame));
 
         return {
           expression,
           result,
           location,
           tokenPos,
           cursorPos,
           extra
@@ -30745,37 +30813,71 @@ function isDebugLine(selectedFrame, sele
 
   return selectedFrame.location.sourceId == selectedLocation.sourceId && selectedFrame.location.line == selectedLocation.line;
 }
 
 function isDocumentReady(selectedSource, selectedLocation) {
   return selectedLocation && (0, _source.isLoaded)(selectedSource) && (0, _sourceDocuments.hasDocument)(selectedLocation.sourceId);
 }
 
-class HighlightLine extends _react.PureComponent {
+class HighlightLine extends _react.Component {
+  constructor(...args) {
+    var _temp;
+
+    return _temp = super(...args), this.isStepping = false, this.previousEditorLine = null, _temp;
+  }
+
+  shouldComponentUpdate(nextProps) {
+    const { selectedLocation, selectedSource } = nextProps;
+    return this.shouldSetHighlightLine(selectedLocation, selectedSource);
+  }
+
+  shouldSetHighlightLine(selectedLocation, selectedSource) {
+    const { sourceId, line } = selectedLocation;
+    const editorLine = (0, _editor.toEditorLine)(sourceId, line);
+
+    if (!isDocumentReady(selectedSource, selectedLocation)) {
+      return false;
+    }
+
+    if (this.isStepping && editorLine === this.previousEditorLine) {
+      return false;
+    }
+
+    return true;
+  }
+
   componentDidUpdate(prevProps) {
-    const { selectedLocation, selectedFrame, selectedSource } = this.props;
+    const {
+      pauseCommand,
+      selectedLocation,
+      selectedFrame,
+      selectedSource
+    } = this.props;
+    if (pauseCommand) {
+      this.isStepping = true;
+    }
 
     this.clearHighlightLine(prevProps.selectedLocation, prevProps.selectedSource);
-
     this.setHighlightLine(selectedLocation, selectedFrame, selectedSource);
   }
 
   setHighlightLine(selectedLocation, selectedFrame, selectedSource) {
-    if (!isDocumentReady(selectedSource, selectedLocation)) {
-      return;
-    }
-
     const { sourceId, line } = selectedLocation;
+    if (!this.shouldSetHighlightLine(selectedLocation, selectedSource)) {
+      return;
+    }
+    this.isStepping = false;
+    const editorLine = (0, _editor.toEditorLine)(sourceId, line);
+    this.previousEditorLine = editorLine;
 
     if (!line || isDebugLine(selectedFrame, selectedLocation)) {
       return;
     }
 
-    const editorLine = (0, _editor.toEditorLine)(sourceId, line);
     const doc = (0, _sourceDocuments.getDocument)(sourceId);
     doc.addLineClass(editorLine, "line", "highlight-line");
   }
 
   clearHighlightLine(selectedLocation, selectedSource) {
     if (!isDocumentReady(selectedSource, selectedLocation)) {
       return;
     }
@@ -30788,16 +30890,17 @@ class HighlightLine extends _react.PureC
 
   render() {
     return null;
   }
 }
 
 exports.HighlightLine = HighlightLine;
 exports.default = (0, _reactRedux.connect)(state => ({
+  pauseCommand: (0, _selectors.getPauseCommand)(state),
   selectedFrame: (0, _selectors.getVisibleSelectedFrame)(state),
   selectedLocation: (0, _selectors.getSelectedLocation)(state),
   selectedSource: (0, _selectors.getSelectedSource)(state)
 }))(HighlightLine);
 
 /***/ }),
 
 /***/ 1797:
@@ -31576,52 +31679,76 @@ function jumpToMappedSelectedLocation() 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
 
 exports.updateFrameLocation = updateFrameLocation;
+exports.mapDisplayNames = mapDisplayNames;
 exports.mapFrames = mapFrames;
 
 var _selectors = __webpack_require__(3590);
 
+var _ast = __webpack_require__(1638);
+
 function updateFrameLocation(frame, sourceMaps) {
   return sourceMaps.getOriginalLocation(frame.location).then(loc => _extends({}, frame, {
     location: loc,
     generatedLocation: frame.generatedLocation || frame.location
   }));
 }
 
 function updateFrameLocations(frames, sourceMaps) {
   if (!frames || frames.length == 0) {
     return Promise.resolve(frames);
   }
 
   return Promise.all(frames.map(frame => updateFrameLocation(frame, sourceMaps)));
 }
 
-/**
- * Map call stack frame locations to original locations.
+function mapDisplayNames(frames, getState) {
+  return frames.map(frame => {
+    const source = (0, _selectors.getSource)(getState(), frame.location.sourceId);
+    const symbols = (0, _selectors.getSymbols)(getState(), source);
+
+    if (!symbols || !symbols.functions) {
+      return frame;
+    }
+
+    const originalFunction = (0, _ast.findClosestFunction)(symbols.functions, frame.location);
+
+    if (!originalFunction) {
+      return frame;
+    }
+
+    const originalDisplayName = originalFunction.name;
+    return _extends({}, frame, { originalDisplayName });
+  });
+}
+
+/**
+ * Map call stack frame locations and display names to originals.
  * e.g.
  * 1. When the debuggee pauses
  * 2. When a source is pretty printed
- *
+ * 3. When symbols are loaded
  * @memberof actions/pause
  * @static
  */
 function mapFrames() {
   return async function ({ dispatch, getState, sourceMaps }) {
     const frames = (0, _selectors.getFrames)(getState());
     if (!frames) {
       return;
     }
 
-    const mappedFrames = await updateFrameLocations(frames, sourceMaps);
+    let mappedFrames = await updateFrameLocations(frames, sourceMaps);
+    mappedFrames = mapDisplayNames(mappedFrames, getState);
 
     dispatch({
       type: "MAP_FRAMES",
       frames: mappedFrames
     });
   };
 }
 
@@ -33921,16 +34048,17 @@ const pref = Services.pref;
 if (isDevelopment()) {
   pref("devtools.debugger.alphabetize-outline", false);
   pref("devtools.debugger.auto-pretty-print", true);
   pref("devtools.source-map.client-service.enabled", true);
   pref("devtools.debugger.pause-on-exceptions", false);
   pref("devtools.debugger.ignore-caught-exceptions", false);
   pref("devtools.debugger.call-stack-visible", true);
   pref("devtools.debugger.scopes-visible", true);
+  pref("devtools.debugger.component-visible", true);
   pref("devtools.debugger.workers-visible", true);
   pref("devtools.debugger.expressions-visible", true);
   pref("devtools.debugger.breakpoints-visible", true);
   pref("devtools.debugger.start-panel-collapsed", false);
   pref("devtools.debugger.end-panel-collapsed", false);
   pref("devtools.debugger.tabs", "[]");
   pref("devtools.debugger.tabsBlackBoxed", "[]");
   pref("devtools.debugger.ui.framework-grouping-on", true);
@@ -33963,16 +34091,17 @@ if (isDevelopment()) {
 const prefs = new PrefsHelper("devtools", {
   alphabetizeOutline: ["Bool", "debugger.alphabetize-outline"],
   autoPrettyPrint: ["Bool", "debugger.auto-pretty-print"],
   clientSourceMapsEnabled: ["Bool", "source-map.client-service.enabled"],
   pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
   ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"],
   callStackVisible: ["Bool", "debugger.call-stack-visible"],
   scopesVisible: ["Bool", "debugger.scopes-visible"],
+  componentVisible: ["Bool", "debugger.component-visible"],
   workersVisible: ["Bool", "debugger.workers-visible"],
   breakpointsVisible: ["Bool", "debugger.breakpoints-visible"],
   expressionsVisible: ["Bool", "debugger.expressions-visible"],
   startPanelCollapsed: ["Bool", "debugger.start-panel-collapsed"],
   endPanelCollapsed: ["Bool", "debugger.end-panel-collapsed"],
   frameworkGroupingOn: ["Bool", "debugger.ui.framework-grouping-on"],
   tabs: ["Json", "debugger.tabs", []],
   tabsBlackBoxed: ["Json", "debugger.tabsBlackBoxed", []],
@@ -37216,34 +37345,43 @@ function annotateBabelAsyncFrames(frames
   const isBabelFrame = frameIndex => babelFrameIndexes.includes(frameIndex);
 
   return frames.map((frame, frameIndex) => isBabelFrame(frameIndex) ? _extends({}, frame, { library: "Babel" }) : frame);
 }
 
 // Receives an array of frames and looks for babel async
 // call stack groups.
 function getBabelFrameIndexes(frames) {
-  const startIndexes = getFrameIndices(frames, (displayName, url) => url.match(/regenerator-runtime/i) && displayName === "tryCatch");
-
-  const endIndexes = getFrameIndices(frames, (displayName, url) => displayName === "_asyncToGenerator/<" || url.match(/_microtask/i) && displayName === "flush");
+  const startIndexes = frames.reduce((accumulator, frame, index) => {
+    if ((0, _getFrameUrl.getFrameUrl)(frame).match(/regenerator-runtime/i) && frame.displayName === "tryCatch") {
+      return [...accumulator, index];
+    }
+    return accumulator;
+  }, []);
+
+  const endIndexes = frames.reduce((accumulator, frame, index) => {
+    if ((0, _getFrameUrl.getFrameUrl)(frame).match(/_microtask/i) && frame.displayName === "flush") {
+      return [...accumulator, index];
+    }
+    if (frame.displayName === "_asyncToGenerator/<") {
+      return [...accumulator, index + 1];
+    }
+    return accumulator;
+  }, []);
 
   if (startIndexes.length != endIndexes.length || startIndexes.length === 0) {
     return frames;
   }
 
   // Receives an array of start and end index tuples and returns
   // an array of async call stack index ranges.
   // e.g. [[1,3], [5,7]] => [[1,2,3], [5,6,7]]
   return (0, _lodash.flatMap)((0, _lodash.zip)(startIndexes, endIndexes), ([startIndex, endIndex]) => (0, _lodash.range)(startIndex, endIndex + 1));
 }
 
-function getFrameIndices(frames, predicate) {
-  return frames.reduce((accumulator, frame, index) => predicate(frame.displayName, (0, _getFrameUrl.getFrameUrl)(frame)) ? [...accumulator, index] : accumulator, []);
-}
-
 /***/ }),
 
 /***/ 3609:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
@@ -37397,17 +37535,18 @@ const displayNameMap = {
 };
 
 function mapDisplayNames(frame, library) {
   const { displayName } = frame;
   return displayNameMap[library] && displayNameMap[library][displayName] || displayName;
 }
 
 function formatDisplayName(frame, { shouldMapDisplayName = true } = {}) {
-  let { displayName, library } = frame;
+  let { displayName, originalDisplayName, library } = frame;
+  displayName = originalDisplayName || displayName;
   if (library && shouldMapDisplayName) {
     displayName = mapDisplayNames(frame, library);
   }
 
   displayName = simplifyDisplayName(displayName);
   return (0, _utils.endTruncateStr)(displayName, 25);
 }
 
@@ -38301,16 +38440,121 @@ function formatPausePoints(text, nodes) 
     lines[line - 1] = insertStrtAt(lines[line - 1], column, `/*${types} ${num}*/`);
   });
 
   return lines.join("\n");
 }
 
 /***/ }),
 
+/***/ 3623:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _react = __webpack_require__(0);
+
+var _react2 = _interopRequireDefault(_react);
+
+var _redux = __webpack_require__(3593);
+
+var _reactRedux = __webpack_require__(3592);
+
+var _actions = __webpack_require__(1354);
+
+var _actions2 = _interopRequireDefault(_actions);
+
+var _firefox = __webpack_require__(1500);
+
+var _selectors = __webpack_require__(3590);
+
+var _devtoolsReps = __webpack_require__(1408);
+
+var _preview = __webpack_require__(1807);
+
+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/>. */
+
+const { createNode, getChildren } = _devtoolsReps.ObjectInspectorUtils.node;
+const { loadItemProperties } = _devtoolsReps.ObjectInspectorUtils.loadProperties;
+
+class FrameworkComponent extends _react.PureComponent {
+  async componentWillMount() {
+    const expression = "this;";
+    const { selectedFrame, setPopupObjectProperties } = this.props;
+    const value = selectedFrame.this;
+
+    const root = createNode(null, expression, expression, { value });
+    const properties = await loadItemProperties(root, _firefox.createObjectClient);
+    if (properties) {
+      setPopupObjectProperties(value, properties);
+    }
+  }
+
+  renderReactComponent() {
+    const { selectedFrame, popupObjectProperties } = this.props;
+    const expression = "this;";
+    const value = selectedFrame.this;
+    const root = {
+      name: expression,
+      path: expression,
+      contents: { value }
+    };
+
+    const loadedRootProperties = popupObjectProperties[value.actor];
+
+    let roots = getChildren({
+      item: root,
+      loadedProperties: new Map([[root.path, loadedRootProperties]])
+    });
+
+    roots = roots.filter(r => ["state", "props"].includes(r.name));
+
+    return _react2.default.createElement(
+      "div",
+      { className: "pane framework-component" },
+      _react2.default.createElement(_devtoolsReps.ObjectInspector, {
+        roots: roots,
+        autoExpandAll: false,
+        autoExpandDepth: 0,
+        disableWrap: true,
+        disabledFocus: true,
+        dimTopLevelWindow: true,
+        createObjectClient: grip => (0, _firefox.createObjectClient)(grip)
+      })
+    );
+  }
+
+  render() {
+    const { selectedFrame } = this.props;
+    if ((0, _preview.isReactComponent)(selectedFrame.this)) {
+      return this.renderReactComponent();
+    }
+
+    return null;
+  }
+}
+
+exports.default = (0, _reactRedux.connect)(state => {
+  return {
+    selectedFrame: (0, _selectors.getSelectedFrame)(state),
+    popupObjectProperties: (0, _selectors.getAllPopupObjectProperties)(state)
+  };
+}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(FrameworkComponent);
+
+/***/ }),
+
 /***/ 363:
 /***/ (function(module, exports) {
 
 module.exports = "<!-- 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/. --><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\"><path fill=\"black\" id=\"svg_1\" fill-rule=\"evenodd\" d=\"m4.55195,12.97461l7.4,-5l-7.4,-5l0,10zm-0.925,0l0,-10c0,-0.785 0.8,-1.264 1.415,-0.848l7.4,5c0.58,0.392 0.58,1.304 0,1.696l-7.4,5c-0.615,0.416 -1.415,-0.063 -1.415,-0.848z\"></path></svg>"
 
 /***/ }),
 
 /***/ 364:
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -992,20 +992,17 @@ let ASTs = new Map();
 function _parse(code, opts) {
   return babylon.parse(code, _extends({}, opts, {
     tokens: true
   }));
 }
 
 const sourceOptions = {
   generated: {
-    tokens: true,
-    plugins: [
-      "objectRestSpread"
-    ]
+    tokens: true
   },
   original: {
     sourceType: "unambiguous",
     tokens: true,
     plugins: ["jsx", "flow", "doExpressions", "objectRestSpread", "classProperties", "exportDefaultFrom", "exportNamespaceFrom", "asyncGenerators", "functionBind", "functionSent", "dynamicImport"]
   }
 };
 
@@ -40560,9 +40557,9 @@ function listCacheHas(key) {
 }
 
 module.exports = listCacheHas;
 
 
 /***/ })
 
 /******/ });
-});
+});
\ No newline at end of file
--- a/devtools/client/preferences/debugger.js
+++ b/devtools/client/preferences/debugger.js
@@ -24,16 +24,17 @@ pref("devtools.debugger.ui.panes-workers
 pref("devtools.debugger.ui.panes-instruments-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
 pref("devtools.debugger.ui.variables-sorting-enabled", true);
 pref("devtools.debugger.ui.variables-only-enum-visible", false);
 pref("devtools.debugger.ui.variables-searchbox-visible", false);
 pref("devtools.debugger.ui.framework-grouping-on", true);
 pref("devtools.debugger.call-stack-visible", true);
 pref("devtools.debugger.scopes-visible", true);
+pref("devtools.debugger.component-visible", true);
 pref("devtools.debugger.workers-visible", true);
 pref("devtools.debugger.breakpoints-visible", true);
 pref("devtools.debugger.expressions-visible", true);
 pref("devtools.debugger.start-panel-collapsed", false);
 pref("devtools.debugger.end-panel-collapsed", false);
 pref("devtools.debugger.tabs", "[]");
 pref("devtools.debugger.tabsBlackBoxed", "[]");
 pref("devtools.debugger.pending-selected-location", "{}");
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -118,32 +118,44 @@ StructuredCloneCallbacksFreeTransfer(uin
 {
   StructuredCloneHolderBase* holder =
     static_cast<StructuredCloneHolderBase*>(aClosure);
   MOZ_ASSERT(holder);
   return holder->CustomFreeTransferHandler(aTag, aOwnership, aContent,
                                            aExtraData);
 }
 
+bool
+StructuredCloneCallbacksCanTransfer(JSContext* aCx,
+                                    JS::Handle<JSObject*> aObject,
+                                    void* aClosure)
+{
+  StructuredCloneHolderBase* holder =
+    static_cast<StructuredCloneHolderBase*>(aClosure);
+  MOZ_ASSERT(holder);
+  return holder->CustomCanTransferHandler(aCx, aObject);
+}
+
 void
 StructuredCloneCallbacksError(JSContext* aCx,
                               uint32_t aErrorId)
 {
   NS_WARNING("Failed to clone data.");
 }
 
 } // anonymous namespace
 
 const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
   StructuredCloneCallbacksRead,
   StructuredCloneCallbacksWrite,
   StructuredCloneCallbacksError,
   StructuredCloneCallbacksReadTransfer,
   StructuredCloneCallbacksWriteTransfer,
-  StructuredCloneCallbacksFreeTransfer
+  StructuredCloneCallbacksFreeTransfer,
+  StructuredCloneCallbacksCanTransfer,
 };
 
 // StructuredCloneHolderBase class
 
 StructuredCloneHolderBase::StructuredCloneHolderBase(StructuredCloneScope aScope)
   : mStructuredCloneScope(aScope)
 #ifdef DEBUG
   , mClearCalled(false)
@@ -235,16 +247,23 @@ void
 StructuredCloneHolderBase::CustomFreeTransferHandler(uint32_t aTag,
                                                      JS::TransferableOwnership aOwnership,
                                                      void* aContent,
                                                      uint64_t aExtraData)
 {
   MOZ_CRASH("Nothing to free.");
 }
 
+bool
+StructuredCloneHolderBase::CustomCanTransferHandler(JSContext* aCx,
+                                                    JS::Handle<JSObject*> aObj)
+{
+  return false;
+}
+
 // StructuredCloneHolder class
 
 StructuredCloneHolder::StructuredCloneHolder(CloningSupport aSupportsCloning,
                                              TransferringSupport aSupportsTransferring,
                                              StructuredCloneScope aScope)
   : StructuredCloneHolderBase(aScope)
   , mSupportsCloning(aSupportsCloning == CloningSupported)
   , mSupportsTransferring(aSupportsTransferring == TransferringSupported)
@@ -1216,32 +1235,40 @@ StructuredCloneHolder::CustomWriteTransf
   {
     MessagePort* port = nullptr;
     nsresult rv = UNWRAP_OBJECT(MessagePort, &obj, port);
     if (NS_SUCCEEDED(rv)) {
       // We use aExtraData to store the index of this new port identifier.
       *aExtraData = mPortIdentifiers.Length();
       MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
 
+      if (!port->CanBeCloned()) {
+        return false;
+      }
+
       port->CloneAndDisentangle(*identifier);
 
       *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
       *aOwnership = JS::SCTAG_TMO_CUSTOM;
       *aContent = nullptr;
 
       return true;
     }
 
     if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
         mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
       OffscreenCanvas* canvas = nullptr;
       rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
       if (NS_SUCCEEDED(rv)) {
         MOZ_ASSERT(canvas);
 
+        if (canvas->IsNeutered()) {
+          return false;
+        }
+
         *aExtraData = 0;
         *aTag = SCTAG_DOM_CANVAS;
         *aOwnership = JS::SCTAG_TMO_CUSTOM;
         *aContent = canvas->ToCloneData();
         MOZ_ASSERT(*aContent);
         canvas->SetNeutered();
 
         return true;
@@ -1310,16 +1337,52 @@ StructuredCloneHolder::CustomFreeTransfe
     ImageBitmapCloneData* data =
       static_cast<ImageBitmapCloneData*>(aContent);
     delete data;
     return;
   }
 }
 
 bool
+StructuredCloneHolder::CustomCanTransferHandler(JSContext* aCx,
+                                                JS::Handle<JSObject*> aObj)
+{
+  if (!mSupportsTransferring) {
+    return false;
+  }
+
+  JS::Rooted<JSObject*> obj(aCx, aObj);
+
+  {
+    MessagePort* port = nullptr;
+    nsresult rv = UNWRAP_OBJECT(MessagePort, &obj, port);
+    if (NS_SUCCEEDED(rv)) {
+      return true;
+    }
+
+    if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
+        mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
+      OffscreenCanvas* canvas = nullptr;
+      rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
+      if (NS_SUCCEEDED(rv)) {
+        return true;
+      }
+
+      ImageBitmap* bitmap = nullptr;
+      rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
+      if (NS_SUCCEEDED(rv)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+bool
 StructuredCloneHolder::TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts)
 {
   nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
 
   aPorts.Clear();
   for (uint32_t i = 0, len = ports.Length(); i < len; ++i) {
     if (!aPorts.AppendElement(ports[i].forget(), fallible)) {
       return false;
--- a/dom/base/StructuredCloneHolder.h
+++ b/dom/base/StructuredCloneHolder.h
@@ -83,16 +83,20 @@ public:
                              uint64_t* aExtraData);
 
   virtual void
   CustomFreeTransferHandler(uint32_t aTag,
                             JS::TransferableOwnership aOwnership,
                             void* aContent,
                             uint64_t aExtraData);
 
+  virtual bool
+  CustomCanTransferHandler(JSContext* aCx,
+                           JS::Handle<JSObject*> aObj);
+
   // These methods are what you should use to read/write data.
 
   // Execute the serialization of aValue using the Structured Clone Algorithm.
   // The data can read back using Read().
   bool Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue);
 
   // Like Write() but it supports the transferring of objects and handling
@@ -278,16 +282,19 @@ public:
                                           void** aContent,
                                           uint64_t* aExtraData) override;
 
   virtual void CustomFreeTransferHandler(uint32_t aTag,
                                          JS::TransferableOwnership aOwnership,
                                          void* aContent,
                                          uint64_t aExtraData) override;
 
+  virtual bool CustomCanTransferHandler(JSContext* aCx,
+                                        JS::Handle<JSObject*> aObj) override;
+
   // These 2 static methods are useful to read/write fully serializable objects.
   // They can be used by custom StructuredCloneHolderBase classes to
   // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
 
   static JSObject* ReadFullySerializableObjects(JSContext* aCx,
                                                 JSStructuredCloneReader* aReader,
                                                 uint32_t aTag);
 
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -608,19 +608,21 @@ public:
    */
 
   nsIDocument* GetUncomposedDoc() const
   {
     return IsInUncomposedDoc() ? OwnerDoc() : nullptr;
   }
 
   /**
-   * This method returns the owner doc if the node is in the
-   * composed document (as defined in the Shadow DOM spec), otherwise
-   * it returns null.
+   * This method returns the owner document if the node is connected to it
+   * (as defined in the DOM spec), otherwise it returns null.
+   * In other words, returns non-null even in the case the node is in
+   * Shadow DOM, if there is a possibly shadow boundary crossing path from
+   * the node to its owner document.
    */
   nsIDocument* GetComposedDoc() const
   {
     return IsInShadowTree() ?
       GetComposedDocInternal() : GetUncomposedDoc();
   }
 
   /**
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -695,17 +695,18 @@ nsresult
 GetAddInfoCallback(JSContext* aCx, void* aClosure)
 {
   static const JSStructuredCloneCallbacks kStructuredCloneCallbacks = {
     nullptr /* read */,
     StructuredCloneWriteCallback /* write */,
     nullptr /* reportError */,
     nullptr /* readTransfer */,
     nullptr /* writeTransfer */,
-    nullptr /* freeTransfer */
+    nullptr /* freeTransfer */,
+    nullptr /* canTransfer */
   };
 
   MOZ_ASSERT(aCx);
 
   auto* data = static_cast<GetAddInfoClosure*>(aClosure);
   MOZ_ASSERT(data);
 
   data->mCloneWriteInfo.mOffsetToKeyProp = 0;
@@ -1318,16 +1319,17 @@ IDBObjectStore::DeserializeValue(JSConte
   JSAutoRequest ar(aCx);
 
   static const JSStructuredCloneCallbacks callbacks = {
     CommonStructuredCloneReadCallback,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
+    nullptr,
     nullptr
   };
 
   // FIXME: Consider to use StructuredCloneHolder here and in other
   //        deserializing methods.
   if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
                               JS::StructuredCloneScope::SameProcessSameThread,
                               aValue, &callbacks, &aCloneReadInfo)) {
@@ -1491,16 +1493,17 @@ private:
   DeserializeIndexValue(JSContext* aCx, JS::MutableHandle<JS::Value> aValue)
   {
     static const JSStructuredCloneCallbacks callbacks = {
       CommonStructuredCloneReadCallback,
       nullptr,
       nullptr,
       nullptr,
       nullptr,
+      nullptr,
       nullptr
     };
 
     if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData,
                                 JS_STRUCTURED_CLONE_VERSION,
                                 JS::StructuredCloneScope::SameProcessSameThread,
                                 aValue, &callbacks, &mCloneReadInfo)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
@@ -1604,16 +1607,17 @@ private:
   DeserializeUpgradeValue(JSContext* aCx, JS::MutableHandle<JS::Value> aValue)
   {
     static const JSStructuredCloneCallbacks callbacks = {
       CommonStructuredCloneReadCallback,
       nullptr,
       nullptr,
       nullptr,
       nullptr,
+      nullptr,
       nullptr
     };
 
     if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData,
                                 JS_STRUCTURED_CLONE_VERSION,
                                 JS::StructuredCloneScope::SameProcessSameThread,
                                 aValue, &callbacks, &mCloneReadInfo)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -199,16 +199,17 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEvent
 NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
 
 MessagePort::MessagePort(nsIGlobalObject* aGlobal)
   : DOMEventTargetHelper(aGlobal)
   , mInnerID(0)
   , mMessageQueueEnabled(false)
   , mIsKeptAlive(false)
+  , mHasBeenTransferredOrClosed(false)
 {
   MOZ_ASSERT(aGlobal);
 
   mIdentifier = new MessagePortIdentifier();
   mIdentifier->neutered() = true;
   mIdentifier->sequenceId() = 0;
 }
 
@@ -496,16 +497,17 @@ MessagePort::Dispatch()
   }
 
   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(mPostMessageRunnable));
 }
 
 void
 MessagePort::Close()
 {
+  mHasBeenTransferredOrClosed = true;
   CloseInternal(true /* aSoftly */);
 }
 
 void
 MessagePort::CloseForced()
 {
   CloseInternal(false /* aSoftly */);
 }
@@ -720,16 +722,19 @@ MessagePort::Disentangle()
 
   UpdateMustKeepAlive();
 }
 
 void
 MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
 {
   MOZ_ASSERT(mIdentifier);
+  MOZ_ASSERT(!mHasBeenTransferredOrClosed);
+
+  mHasBeenTransferredOrClosed = true;
 
   // We can clone a port that has already been transfered. In this case, on the
   // otherside will have a neutered port. Here we set neutered to true so that
   // we are safe in case a early return.
   aIdentifier.neutered() = true;
 
   if (mState > eStateEntangled) {
     return;
--- a/dom/messagechannel/MessagePort.h
+++ b/dom/messagechannel/MessagePort.h
@@ -69,16 +69,21 @@ public:
   void SetOnmessage(EventHandlerNonNull* aCallback);
 
   IMPL_EVENT_HANDLER(messageerror)
 
   // Non WebIDL methods
 
   void UnshippedEntangle(MessagePort* aEntangledPort);
 
+  bool CanBeCloned() const
+  {
+    return !mHasBeenTransferredOrClosed;
+  }
+
   void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
 
   void CloseForced();
 
   // These methods are useful for MessagePortChild
 
   void Entangled(nsTArray<ClonedMessageData>& aMessages);
   void MessagesReceived(nsTArray<ClonedMessageData>& aMessages);
@@ -177,14 +182,20 @@ private:
 
   uint64_t mInnerID;
 
   State mState;
 
   bool mMessageQueueEnabled;
 
   bool mIsKeptAlive;
+
+  // mHasBeenTransferredOrClosed is used to know if this port has been manually
+  // closed or transferred via postMessage. Note that if the entangled port is
+  // closed, this port is closed as well (see mState) but, just because close()
+  // has not been called directly, by spec, this port can still be transferred.
+  bool mHasBeenTransferredOrClosed;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MessagePort_h
--- a/gfx/2d/DrawCommands.h
+++ b/gfx/2d/DrawCommands.h
@@ -235,16 +235,23 @@ public:
     CLONE_INTO(DrawFilterCommand)(mFilter, mSourceRect, mDestPoint, mOptions);
   }
 
   virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
   {
     RefPtr<FilterNode> filter = mFilter;
     if (mFilter->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
       filter = static_cast<FilterNodeCapture*>(filter.get())->Validate(aDT);
+
+      // This can happen if the FilterNodeCapture is unable to create a
+      // backing FilterNode on the target backend. Normally this would be
+      // handled by the painting code, but here there's not much we can do.
+      if (!filter) {
+        return;
+      }
     }
     aDT->DrawFilter(filter, mSourceRect, mDestPoint, mOptions);
   }
 
   void Log(TreeLog& aStream) const override
   {
     aStream << "[DrawFilter surf=" << mFilter;
     aStream << " src=" << mSourceRect;
--- a/gfx/2d/FilterNodeD2D1.cpp
+++ b/gfx/2d/FilterNodeD2D1.cpp
@@ -197,32 +197,36 @@ uint32_t ConvertValue(FilterType aType, 
       aValue = D2DTurbulenceNoise(aValue);
     }
     break;
   case FilterType::COMPOSITE:
     if (aAttribute == ATT_COMPOSITE_OPERATOR) {
       aValue = D2DFilterCompositionMode(aValue);
     }
     break;
+  default:
+    break;
   }
 
   return aValue;
 }
 
 void ConvertValue(FilterType aType, uint32_t aAttribute, IntSize &aValue)
 {
   switch (aType) {
   case FilterType::MORPHOLOGY:
     if (aAttribute == ATT_MORPHOLOGY_RADII) {
       aValue.width *= 2;
       aValue.width += 1;
       aValue.height *= 2;
       aValue.height += 1;
     }
     break;
+  default:
+    break;
   }
 }
 
 UINT32
 GetD2D1InputForInput(FilterType aType, uint32_t aIndex)
 {
   return aIndex;
 }
@@ -436,32 +440,36 @@ GetD2D1PropForAttribute(FilterType aType
       CONVERT_PROP(DISTANT_SPECULAR_KERNEL_UNIT_LENGTH, DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH);
     }
     break;
   case FilterType::CROP:
     switch (aIndex) {
       CONVERT_PROP(CROP_RECT, CROP_PROP_RECT);
     }
     break;
+  default:
+    break;
   }
 
   return UINT32_MAX;
 }
 
 bool
 GetD2D1PropsForIntSize(FilterType aType, uint32_t aIndex, UINT32 *aPropWidth, UINT32 *aPropHeight)
 {
   switch (aType) {
   case FilterType::MORPHOLOGY:
     if (aIndex == ATT_MORPHOLOGY_RADII) {
       *aPropWidth = D2D1_MORPHOLOGY_PROP_WIDTH;
       *aPropHeight = D2D1_MORPHOLOGY_PROP_HEIGHT;
       return true;
     }
     break;
+  default:
+    break;
   }
   return false;
 }
 
 static inline REFCLSID GetCLDIDForFilterType(FilterType aType)
 {
   switch (aType) {
   case FilterType::COLOR_MATRIX:
@@ -509,16 +517,18 @@ static inline REFCLSID GetCLDIDForFilter
   case FilterType::DISTANT_SPECULAR:
     return CLSID_D2D1DistantSpecular;
   case FilterType::CROP:
     return CLSID_D2D1Crop;
   case FilterType::PREMULTIPLY:
     return CLSID_D2D1Premultiply;
   case FilterType::UNPREMULTIPLY:
     return CLSID_D2D1UnPremultiply;
+  default:
+    break;
   }
   return GUID_NULL;
 }
 
 static bool
 IsTransferFilterType(FilterType aType)
 {
   switch (aType) {
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -860,17 +860,17 @@ SourceSurfaceImage::GetTextureClient(Kno
   }
   if (textureClient) {
     textureClient->SyncWithObject(aForwarder->GetSyncObject());
     entry.OrInsert([&textureClient](){ return textureClient; });
     return textureClient;
   }
 
   // Remove the speculatively added entry.
-  mTextureClients.Remove(aForwarder->GetSerial());
+  entry.OrRemove();
   return nullptr;
 }
 
 ImageContainer::ProducerID
 ImageContainer::AllocateProducerID()
 {
   // Callable on all threads.
   static Atomic<ImageContainer::ProducerID> sProducerID(0u);
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -862,17 +862,18 @@ APZCTreeManager::PrepareNodeForLayer(con
   // that is supposed to scroll together is split into multiple layers because of
   // e.g. non-scrolling content interleaved in z-index order.
   ScrollableLayerGuid guid(aLayersId, aMetrics);
   auto insertResult = aState.mApzcMap.insert(std::make_pair(guid, static_cast<AsyncPanZoomController*>(nullptr)));
   if (!insertResult.second) {
     apzc = insertResult.first->second;
     PrintAPZCInfo(aLayer, apzc);
   }
-  APZCTM_LOG("Found APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), guid.mLayersId, guid.mScrollId);
+  APZCTM_LOG("Found APZC %p for layer %p with identifiers %" PRIx64 " %" PRId64 "\n",
+      apzc, aLayer.GetLayer(), uint64_t(guid.mLayersId), guid.mScrollId);
 
   // If we haven't encountered a layer already with the same metrics, then we need to
   // do the full reuse-or-make-an-APZC algorithm, which is contained inside the block
   // below.
   if (apzc == nullptr) {
     apzc = aLayer.GetApzc();
 
     // If the content represented by the scrollable layer has changed (which may
@@ -933,17 +934,18 @@ APZCTreeManager::PrepareNodeForLayer(con
       // be in the tree. These pointers will get reset properly as we continue
       // building the tree. Also remove it from the set of nodes that are going
       // to be destroyed, because it's going to remain active.
       aState.mNodesToDestroy.RemoveElement(node);
       node->SetPrevSibling(nullptr);
       node->SetLastChild(nullptr);
     }
 
-    APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
+    APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRIx64 " %" PRId64 "\n",
+        apzc, aLayer.GetLayer(), uint64_t(aLayersId), aMetrics.GetScrollId());
 
     apzc->NotifyLayersUpdated(aLayer.Metadata(), aState.mIsFirstPaint,
         aLayersId == aState.mOriginatingLayersId);
 
     // Since this is the first time we are encountering an APZC with this guid,
     // the node holding it must be the primary holder. It may be newly-created
     // or not, depending on whether it went through the newApzc branch above.
     MOZ_ASSERT(node->IsPrimaryHolder() && node->GetApzc() && node->GetApzc()->Matches(guid));
@@ -1082,17 +1084,17 @@ WillHandleInput(const PanGestureOrScroll
 }
 
 void
 APZCTreeManager::FlushApzRepaints(LayersId aLayersId)
 {
   // Previously, paints were throttled and therefore this method was used to
   // ensure any pending paints were flushed. Now, paints are flushed
   // immediately, so it is safe to simply send a notification now.
-  APZCTM_LOG("Flushing repaints for layers id 0x%" PRIx64 "\n", aLayersId);
+  APZCTM_LOG("Flushing repaints for layers id 0x%" PRIx64 "\n", uint64_t(aLayersId));
   RefPtr<GeckoContentController> controller = GetContentController(aLayersId);
   MOZ_ASSERT(controller);
   controller->DispatchToRepaintThread(
     NewRunnableMethod("layers::GeckoContentController::NotifyFlushComplete",
                       controller,
                       &GeckoContentController::NotifyFlushComplete));
 }
 
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -670,25 +670,19 @@ PrepareForSetTargetAPZCNotification(nsIW
     dpElement, &(guid.mPresShellId), &(guid.mScrollId));
   aTargets->AppendElement(guid);
 
   if (!guidIsValid || nsLayoutUtils::HasDisplayPort(dpElement)) {
     return false;
   }
 
   if (!scrollAncestor) {
-    MOZ_ASSERT(false);  // If you hit this, please file a bug with STR.
-
-    // Attempt some sort of graceful handling based on a theory as to why we
-    // reach this point...
-    // If we get here, the document element is non-null, valid, but doesn't have
-    // a displayport. It's possible that the init code in ChromeProcessController
-    // failed for some reason, or the document element got swapped out at some
-    // later time. In this case let's try to set a displayport on the document
-    // element again and bail out on this operation.
+    // This can happen if the document element gets swapped out after ChromeProcessController
+    // runs InitializeRootDisplayport. In this case let's try to set a displayport again and
+    // bail out on this operation.
     APZCCH_LOG("Widget %p's document element %p didn't have a displayport\n",
         aWidget, dpElement.get());
     APZCCallbackHelper::InitializeRootDisplayport(aRootFrame->PresShell());
     return false;
   }
 
   APZCCH_LOG("%p didn't have a displayport, so setting one...\n", dpElement.get());
   bool activated = nsLayoutUtils::CalculateAndSetDisplayPortMargins(
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -103,17 +103,16 @@ WebRenderLayerManager::DoDestroy(bool aI
   if (IsDestroyed()) {
     return;
   }
 
   LayerManager::Destroy();
 
   if (WrBridge()) {
     // Just clear ImageKeys, they are deleted during WebRenderAPI destruction.
-    mImageKeysToDeleteLater.Clear();
     mImageKeysToDelete.Clear();
     // CompositorAnimations are cleared by WebRenderBridgeParent.
     mDiscardedCompositorAnimationsIds.Clear();
     WrBridge()->Destroy(aIsSync);
   }
 
   // Clear this before calling RemoveUnusedAndResetWebRenderUserData(),
   // otherwise that function might destroy some WebRenderAnimationData instances
@@ -293,17 +292,16 @@ WebRenderLayerManager::EndTransactionWit
 
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
   TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart();
 
   for (const auto& key : mImageKeysToDelete) {
     resourceUpdates.DeleteImage(key);
   }
   mImageKeysToDelete.Clear();
-  mImageKeysToDelete.SwapElements(mImageKeysToDeleteLater);
 
   WrBridge()->RemoveExpiredFontKeys(resourceUpdates);
 
   // Skip the synchronization for buffer since we also skip the painting during
   // device-reset status.
   if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
     if (WrBridge()->GetSyncObject() &&
         WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
@@ -401,30 +399,26 @@ WebRenderLayerManager::MakeSnapshotIfReq
   dt->FillRect(dst, pattern);
 
   mTarget = nullptr;
 }
 
 void
 WebRenderLayerManager::AddImageKeyForDiscard(wr::ImageKey key)
 {
-  mImageKeysToDeleteLater.AppendElement(key);
+  mImageKeysToDelete.AppendElement(key);
 }
 
 void
 WebRenderLayerManager::DiscardImages()
 {
   wr::IpcResourceUpdateQueue resources(WrBridge());
-  for (const auto& key : mImageKeysToDeleteLater) {
-    resources.DeleteImage(key);
-  }
   for (const auto& key : mImageKeysToDelete) {
     resources.DeleteImage(key);
   }
-  mImageKeysToDeleteLater.Clear();
   mImageKeysToDelete.Clear();
   WrBridge()->UpdateResources(resources);
 }
 
 void
 WebRenderLayerManager::AddActiveCompositorAnimationId(uint64_t aId)
 {
   // In layers-free mode we track the active compositor animation ids on the
@@ -457,17 +451,16 @@ WebRenderLayerManager::DiscardCompositor
 }
 
 void
 WebRenderLayerManager::DiscardLocalImages()
 {
   // Removes images but doesn't tell the parent side about them
   // This is useful in empty / failed transactions where we created
   // image keys but didn't tell the parent about them yet.
-  mImageKeysToDeleteLater.Clear();
   mImageKeysToDelete.Clear();
 }
 
 void
 WebRenderLayerManager::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
 {
   if (WrBridge()->IPCOpen()) {
     WrBridge()->SendSetLayerObserverEpoch(aLayerObserverEpoch);
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -170,21 +170,16 @@ private:
    * Take a snapshot of the parent context, and copy
    * it into mTarget.
    */
   void MakeSnapshotIfRequired(LayoutDeviceIntSize aSize);
 
 private:
   nsIWidget* MOZ_NON_OWNING_REF mWidget;
   nsTArray<wr::ImageKey> mImageKeysToDelete;
-  // TODO - This is needed because we have some code that creates image keys
-  // and enqueues them for deletion right away which is bad not only because
-  // of poor texture cache usage, but also because images end up deleted before
-  // they are used. This should hopfully be temporary.
-  nsTArray<wr::ImageKey> mImageKeysToDeleteLater;
 
   // Set of compositor animation ids for which there are active animations (as
   // of the last transaction) on the compositor side.
   std::unordered_set<uint64_t> mActiveCompositorAnimationIds;
   // Compositor animation ids for animations that are done now and that we want
   // the compositor to discard information for.
   nsTArray<uint64_t> mDiscardedCompositorAnimationsIds;
 
--- a/intl/hyphenation/glue/hnjalloc.h
+++ b/intl/hyphenation/glue/hnjalloc.h
@@ -26,26 +26,32 @@
 #include <stdio.h> /* ensure stdio.h is loaded before our macros */
 
 #undef FILE
 #define FILE hnjFile
 
 #define fopen(path,mode)      hnjFopen(path,mode)
 #define fclose(file)          hnjFclose(file)
 #define fgets(buf,count,file) hnjFgets(buf,count,file)
+#define feof(file)            hnjFeof(file)
+#define fgetc(file)           hnjFgetc(file)
 
 typedef struct hnjFile_ hnjFile;
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 hnjFile* hnjFopen(const char* aURISpec, const char* aMode);
 
 int hnjFclose(hnjFile* f);
 
 char* hnjFgets(char* s, int n, hnjFile* f);
 
+int hnjFeof(hnjFile* f);
+
+int hnjFgetc(hnjFile* f);
+
 #ifdef __cplusplus
 }
 #endif
 
 
--- a/intl/hyphenation/glue/hnjstdio.cpp
+++ b/intl/hyphenation/glue/hnjstdio.cpp
@@ -17,16 +17,17 @@
 
 #define BUFSIZE 1024
 
 struct hnjFile_ {
     nsCOMPtr<nsIInputStream> mStream;
     char                     mBuffer[BUFSIZE];
     uint32_t                 mCurPos;
     uint32_t                 mLimit;
+    bool                     mEOF;
 };
 
 // replacement for fopen()
 // (not a full substitute: only supports read access)
 hnjFile*
 hnjFopen(const char* aURISpec, const char* aMode)
 {
     // this override only needs to support "r"
@@ -53,16 +54,17 @@ hnjFopen(const char* aURISpec, const cha
     if (NS_FAILED(rv)) {
         return nullptr;
     }
 
     hnjFile *f = new hnjFile;
     f->mStream = instream;
     f->mCurPos = 0;
     f->mLimit = 0;
+    f->mEOF = false;
 
     return f;
 }
 
 // replacement for fclose()
 int
 hnjFclose(hnjFile* f)
 {
@@ -74,46 +76,64 @@ hnjFclose(hnjFile* f)
         result = EOF;
     }
     f->mStream = nullptr;
 
     delete f;
     return result;
 }
 
+// replacement for fgetc()
+int
+hnjFgetc(hnjFile* f)
+{
+    if (f->mCurPos >= f->mLimit) {
+        f->mCurPos = 0;
+
+        nsresult rv = f->mStream->Read(f->mBuffer, BUFSIZE, &f->mLimit);
+        if (NS_FAILED(rv)) {
+            f->mLimit = 0;
+        }
+
+        if (f->mLimit == 0) {
+            f->mEOF = true;
+            return EOF;
+        }
+    }
+
+    return f->mBuffer[f->mCurPos++];
+}
+
 // replacement for fgets()
 // (not a full reimplementation, but sufficient for libhyphen's needs)
 char*
 hnjFgets(char* s, int n, hnjFile* f)
 {
     NS_ASSERTION(s && f, "bad argument to hnjFgets");
 
     int i = 0;
     while (i < n - 1) {
-        if (f->mCurPos < f->mLimit) {
-            char c = f->mBuffer[f->mCurPos++];
-            s[i++] = c;
-            if (c == '\n' || c == '\r') {
-                break;
-            }
-            continue;
+        int c = hnjFgetc(f);
+
+        if (c == EOF) {
+            break;
         }
 
-        f->mCurPos = 0;
+        s[i++] = c;
 
-        nsresult rv = f->mStream->Read(f->mBuffer, BUFSIZE, &f->mLimit);
-        if (NS_FAILED(rv)) {
-            f->mLimit = 0;
-            return nullptr;
-        }
-
-        if (f->mLimit == 0) {
+        if (c == '\n' || c == '\r') {
             break;
         }
     }
 
     if (i == 0) {
         return nullptr; // end of file
     }
 
     s[i] = '\0'; // null-terminate the returned string
     return s;
 }
+
+int
+hnjFeof(hnjFile* f)
+{
+    return f->mEOF ? EOF : 0;
+}
--- a/intl/hyphenation/hyphen/hyphen.c
+++ b/intl/hyphenation/hyphen/hyphen.c
@@ -433,21 +433,35 @@ for (k = 0; k < 2; k++) {
     dict[k]->utf8 = (strcmp(dict[k]->cset, "UTF-8") == 0);
   } else {
     strncpy(dict[k]->cset, dict[0]->cset, sizeof(dict[k]->cset)-1);
     dict[k]->cset[sizeof(dict[k]->cset)-1] = '\0';
     dict[k]->utf8 = dict[0]->utf8;
   }
 
   if (k == 0 || nextlevel) {
-    while (fgets (buf, sizeof(buf), f) != NULL) {
+    while (fgets(buf, sizeof(buf), f) != NULL) {
+      
+      /* discard lines that don't fit in buffer */
+      if (!feof(f) && strchr(buf, '\n') == NULL) {
+        int c;
+        while ((c = fgetc(f)) != '\n' && c != EOF);
+        /* issue warning if not a comment */
+        if (buf[0] != '%') {
+          fprintf(stderr, "Warning: skipping too long pattern (more than %lu chars)\n", sizeof(buf));
+        }
+        continue;
+      }
+      
       if (strncmp(buf, "NEXTLEVEL", 9) == 0) {
-	nextlevel = 1;
-	break;
-      } else if (buf[0] != '%') hnj_hyphen_load_line(buf, dict[k], hashtab);
+        nextlevel = 1;
+        break;
+      } else if (buf[0] != '%') {
+        hnj_hyphen_load_line(buf, dict[k], hashtab);
+      }
     }
   } else if (k == 1) {
     /* default first level: hyphen and ASCII apostrophe */
     if (!dict[0]->utf8) hnj_hyphen_load_line("NOHYPHEN ',-\n", dict[k], hashtab);
     else hnj_hyphen_load_line("NOHYPHEN ',\xe2\x80\x93,\xe2\x80\x99,-\n", dict[k], hashtab);
     strncpy(buf, "1-1\n", MAX_CHARS-1); /* buf rewritten by hnj_hyphen_load here */
     buf[MAX_CHARS-1] = '\0';
     hnj_hyphen_load_line(buf, dict[k], hashtab); /* remove hyphen */
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -290,23 +290,32 @@ typedef bool (*TransferStructuredCloneOp
 /**
  * Called when freeing an unknown transferable object. Note that it
  * should never trigger a garbage collection (and will assert in a
  * debug build if it does.)
  */
 typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership,
                                               void* content, uint64_t extraData, void* closure);
 
+/**
+ * Called when the transferring objects are checked. If this function returns false, the
+ * serialization ends throwing a DataCloneError exception.
+ */
+typedef bool (*CanTransferStructuredCloneOp)(JSContext* cx,
+                                             JS::Handle<JSObject*> obj,
+                                             void* closure);
+
 struct JSStructuredCloneCallbacks {
     ReadStructuredCloneOp read;
     WriteStructuredCloneOp write;
     StructuredCloneErrorOp reportError;
     ReadTransferStructuredCloneOp readTransfer;
     TransferStructuredCloneOp writeTransfer;
     FreeTransferStructuredCloneOp freeTransfer;
+    CanTransferStructuredCloneOp canTransfer;
 };
 
 enum OwnTransferablePolicy {
     OwnsTransferablesIfAny,
     IgnoreTransferablesIfAny,
     NoTransferables
 };
 
--- a/js/public/TrackedOptimizationInfo.h
+++ b/js/public/TrackedOptimizationInfo.h
@@ -33,26 +33,24 @@ namespace JS {
     _(SetProp_TypedObject)                              \
     _(SetProp_DefiniteSlot)                             \
     _(SetProp_Unboxed)                                  \
     _(SetProp_InlineAccess)                             \
     _(SetProp_InlineCache)                              \
                                                         \
     _(GetElem_TypedObject)                              \
     _(GetElem_Dense)                                    \
-    _(GetElem_TypedStatic)                              \
     _(GetElem_TypedArray)                               \
     _(GetElem_String)                                   \
     _(GetElem_Arguments)                                \
     _(GetElem_ArgumentsInlinedConstant)                 \
     _(GetElem_ArgumentsInlinedSwitch)                   \
     _(GetElem_InlineCache)                              \
                                                         \
     _(SetElem_TypedObject)                              \
-    _(SetElem_TypedStatic)                              \
     _(SetElem_TypedArray)                               \
     _(SetElem_Dense)                                    \
     _(SetElem_Arguments)                                \
     _(SetElem_InlineCache)                              \
                                                         \
     _(BinaryArith_Concat)                               \
     _(BinaryArith_SpecializedTypes)                     \
     _(BinaryArith_SpecializedOnBaselineTypes)           \
@@ -118,18 +116,16 @@ namespace JS {
     _(AccessNotTypedObject)                                             \
     _(AccessNotTypedArray)                                              \
     _(AccessNotString)                                                  \
     _(OperandNotString)                                                 \
     _(OperandNotNumber)                                                 \
     _(OperandNotStringOrNumber)                                         \
     _(OperandNotSimpleArith)                                            \
     _(OperandNotEasilyCoercibleToString)                                \
-    _(StaticTypedArrayUint32)                                           \
-    _(StaticTypedArrayCantComputeMask)                                  \
     _(OutOfBounds)                                                      \
     _(GetElemStringNotCached)                                           \
     _(NonNativeReceiver)                                                \
     _(IndexType)                                                        \
     _(SetElemNonDenseNonTANotCached)                                    \
     _(NoSimdJitSupport)                                                 \
     _(SimdTypeNotOptimized)                                             \
     _(UnknownSimdProperty)                                              \
--- a/js/src/builtin/Module.js
+++ b/js/src/builtin/Module.js
@@ -183,19 +183,23 @@ function IsResolvedBinding(resolution)
 }
 
 // 15.2.1.18 GetModuleNamespace(module)
 function GetModuleNamespace(module)
 {
     // Step 1
     assert(IsModule(module), "GetModuleNamespace called with non-module");
 
+    // Until issue https://github.com/tc39/ecma262/issues/1155 is resolved,
+    // violate the spec here and throw if called on an errored module.
+    if (module.status === MODULE_STATUS_EVALUATED_ERROR)
+        throw GetModuleEvaluationError(module);
+
     // Steps 2-3
-    assert(module.status !== MODULE_STATUS_UNINSTANTIATED &&
-           module.status !== MODULE_STATUS_EVALUATED_ERROR,
+    assert(module.status !== MODULE_STATUS_UNINSTANTIATED,
            "Bad module state in GetModuleNamespace");
 
     // Step 4
     let namespace = module.namespace;
 
     // Step 3
     if (typeof namespace === "undefined") {
         let exportedNames = callFunction(module.getExportedNames, module);
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -1750,42 +1750,16 @@ obj_getOwnPropertySymbols(JSContext* cx,
     if (!obj)
         return false;
 
     return GetOwnPropertyKeys(cx, obj,
                               JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY,
                               args.rval());
 }
 
-/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.4: Object.defineProperty(O, P, Attributes) */
-bool
-js::obj_defineProperty(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Steps 1-3.
-    RootedObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, args, "Object.defineProperty", &obj))
-        return false;
-    RootedId id(cx);
-    if (!ToPropertyKey(cx, args.get(1), &id))
-        return false;
-
-    // Steps 4-5.
-    Rooted<PropertyDescriptor> desc(cx);
-    if (!ToPropertyDescriptor(cx, args.get(2), true, &desc))
-        return false;
-
-    // Steps 6-8.
-    if (!DefineProperty(cx, obj, id, desc))
-        return false;
-    args.rval().setObject(*obj);
-    return true;
-}
-
 /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
 static bool
 obj_defineProperties(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Steps 1 and 7. */
     RootedObject obj(cx);
--- a/js/src/builtin/Object.h
+++ b/js/src/builtin/Object.h
@@ -17,50 +17,39 @@ class Value;
 } // namespace JS
 
 namespace js {
 
 // Object constructor native. Exposed only so the JIT can know its address.
 MOZ_MUST_USE bool
 obj_construct(JSContext* cx, unsigned argc, JS::Value* vp);
 
-MOZ_MUST_USE bool
-obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp);
-
 PlainObject*
 ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind = GenericObject,
                  HandleObjectGroup group = nullptr);
 
 PlainObject*
 ObjectCreateWithTemplate(JSContext* cx, HandlePlainObject templateObj);
 
 // Object methods exposed so they can be installed in the self-hosting global.
 MOZ_MUST_USE bool
-obj_create(JSContext* cx, unsigned argc, JS::Value* vp);
+obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp);
 
 MOZ_MUST_USE bool
-obj_defineProperty(JSContext* cx, unsigned argc, JS::Value* vp);
+obj_create(JSContext* cx, unsigned argc, JS::Value* vp);
 
 MOZ_MUST_USE bool
 obj_getOwnPropertyNames(JSContext* cx, unsigned argc, JS::Value* vp);
 
 MOZ_MUST_USE bool
-obj_getPrototypeOf(JSContext* cx, unsigned argc, JS::Value* vp);
-
-
-MOZ_MUST_USE bool
-obj_isExtensible(JSContext* cx, unsigned argc, JS::Value* vp);
-
-MOZ_MUST_USE bool
 obj_toString(JSContext* cx, unsigned argc, JS::Value* vp);
 
 JSString*
 ObjectClassToString(JSContext* cx, HandleObject obj);
 
-// Exposed so SelfHosting.cpp can use it in the OwnPropertyKeys intrinsic
 MOZ_MUST_USE bool
 GetOwnPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, JS::MutableHandleValue rval);
 
 // Exposed for SelfHosting.cpp
 MOZ_MUST_USE bool
 GetOwnPropertyDescriptorToArray(JSContext* cx, unsigned argc, JS::Value* vp);
 
 /*
--- a/js/src/builtin/Object.js
+++ b/js/src/builtin/Object.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // ES stage 4 proposal
 function ObjectGetOwnPropertyDescriptors(O) {
     // Step 1.
     var obj = ToObject(O);
 
     // Step 2.
-    var keys = OwnPropertyKeys(obj);
+    var keys = std_Reflect_ownKeys(obj);
 
     // Step 3.
     var descriptors = {};
 
     // Step 4.
     for (var index = 0, len = keys.length; index < len; index++) {
         var key = keys[index];
 
--- a/js/src/builtin/Reflect.cpp
+++ b/js/src/builtin/Reflect.cpp
@@ -82,18 +82,18 @@ js::Reflect_isExtensible(JSContext* cx, 
     if (!IsExtensible(cx, target, &extensible))
         return false;
     args.rval().setBoolean(extensible);
     return true;
 }
 
 // ES2018 draft rev c164be80f7ea91de5526b33d54e5c9321ed03d3f
 // 26.1.10 Reflect.ownKeys ( target )
-static bool
-Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
+bool
+js::Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject target(cx, NonNullObjectArg(cx, "`target`", "Reflect.ownKeys", args.get(0)));
     if (!target)
         return false;
 
--- a/js/src/builtin/Reflect.h
+++ b/js/src/builtin/Reflect.h
@@ -19,11 +19,14 @@ InitReflect(JSContext* cx, js::HandleObj
 namespace js {
 
 extern MOZ_MUST_USE bool
 Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp);
 
 extern MOZ_MUST_USE bool
 Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp);
 
+extern MOZ_MUST_USE bool
+Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp);
+
 }
 
 #endif /* builtin_Reflect_h */
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -214,77 +214,88 @@ function GetInternalError(msg) {
         return e;
     }
     assert(false, "the catch block should've returned from this function.");
 }
 
 // To be used when a function is required but calling it shouldn't do anything.
 function NullFunction() {}
 
-// Object Rest/Spread Properties proposal
-// Abstract operation: CopyDataProperties (target, source, excluded)
-function CopyDataProperties(target, source, excluded) {
+// ES2019 draft rev 4c2df13f4194057f09b920ee88712e5a70b1a556
+// 7.3.23 CopyDataProperties (target, source, excludedItems)
+function CopyDataProperties(target, source, excludedItems) {
     // Step 1.
     assert(IsObject(target), "target is an object");
 
     // Step 2.
-    assert(IsObject(excluded), "excluded is an object");
+    assert(IsObject(excludedItems), "excludedItems is an object");
 
-    // Steps 3, 6.
+    // Steps 3 and 7.
     if (source === undefined || source === null)
         return;
 
-    // Step 4.a.
-    source = ToObject(source);
-
-    // Step 4.b.
-    var keys = OwnPropertyKeys(source);
+    // Step 4.
+    var from = ToObject(source);
 
     // Step 5.
+    var keys = CopyDataPropertiesOrGetOwnKeys(target, from, excludedItems);
+
+    // Return if we copied all properties in native code.
+    if (keys === null)
+        return;
+
+    // Step 6.
     for (var index = 0; index < keys.length; index++) {
         var key = keys[index];
 
         // We abbreviate this by calling propertyIsEnumerable which is faster
         // and returns false for not defined properties.
-        if (!hasOwn(key, excluded) && callFunction(std_Object_propertyIsEnumerable, source, key))
-            _DefineDataProperty(target, key, source[key]);
+        if (!hasOwn(key, excludedItems) &&
+            callFunction(std_Object_propertyIsEnumerable, from, key))
+        {
+            _DefineDataProperty(target, key, from[key]);
+        }
     }
 
-    // Step 6 (Return).
+    // Step 7 (Return).
 }
 
-// Object Rest/Spread Properties proposal
-// Abstract operation: CopyDataProperties (target, source, excluded)
+// ES2019 draft rev 4c2df13f4194057f09b920ee88712e5a70b1a556
+// 7.3.23 CopyDataProperties (target, source, excludedItems)
 function CopyDataPropertiesUnfiltered(target, source) {
     // Step 1.
     assert(IsObject(target), "target is an object");
 
     // Step 2 (Not applicable).
 
-    // Steps 3, 6.
+    // Steps 3 and 7.
     if (source === undefined || source === null)
         return;
 
-    // Step 4.a.
-    source = ToObject(source);
-
-    // Step 4.b.
-    var keys = OwnPropertyKeys(source);
+    // Step 4.
+    var from = ToObject(source);
 
     // Step 5.
+    var keys = CopyDataPropertiesOrGetOwnKeys(target, from, null);
+
+    // Return if we copied all properties in native code.
+    if (keys === null)
+        return;
+
+    // Step 6.
     for (var index = 0; index < keys.length; index++) {
         var key = keys[index];
 
         // We abbreviate this by calling propertyIsEnumerable which is faster
         // and returns false for not defined properties.
-        if (callFunction(std_Object_propertyIsEnumerable, source, key))
-            _DefineDataProperty(target, key, source[key]);
+        if (callFunction(std_Object_propertyIsEnumerable, from, key))
+            _DefineDataProperty(target, key, from[key]);
     }
 
-    // Step 6 (Return).
+    // Step 7 (Return).
 }
 
 /*************************************** Testing functions ***************************************/
 function outer() {
     return function inner() {
         return "foo";
     };
 }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5484,30 +5484,17 @@ BytecodeEmitter::setOrEmitSetFunName(Par
                                      FunctionPrefixKind prefixKind)
 {
     MOZ_ASSERT(maybeFun->isDirectRHSAnonFunction());
 
     if (maybeFun->isKind(ParseNodeKind::Function)) {
         // Function doesn't have 'name' property at this point.
         // Set function's name at compile time.
         JSFunction* fun = maybeFun->pn_funbox->function();
-
-        // Single node can be emitted multiple times if it appears in
-        // array destructuring default.  If function already has a name,
-        // just return.
-        if (fun->hasInferredName()) {
-#ifdef DEBUG
-            RootedFunction rootedFun(cx, fun);
-            JSAtom* funName = NameToFunctionName(cx, name, prefixKind);
-            if (!funName)
-                return false;
-            MOZ_ASSERT(funName == rootedFun->inferredName());
-#endif
-            return true;
-        }
+        MOZ_ASSERT(!fun->hasInferredName());
 
         fun->setInferredName(name);
         return true;
     }
 
     MOZ_ASSERT(maybeFun->isKind(ParseNodeKind::Class));
 
     uint32_t nameIndex;
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -1285,19 +1285,21 @@ FoldElement(JSContext* cx, ParseNode** n
             name = atom->asPropertyName();
         }
     } else if (key->isKind(ParseNodeKind::Number)) {
         double number = key->pn_dval;
         if (number != ToUint32(number)) {
             // Optimization 2: We have something like expr[3.14]. The number
             // isn't an array index, so it converts to a string ("3.14"),
             // enabling optimization 3 below.
-            JSAtom* atom = ToAtom<NoGC>(cx, DoubleValue(number));
-            if (!atom)
+            JSAtom* atom = NumberToAtom(cx, number);
+            if (!atom) {
+                cx->recoverFromOutOfMemory();
                 return false;
+            }
             name = atom->asPropertyName();
         }
     }
 
     // If we don't have a name, we can't optimize to getprop.
     if (!name)
         return true;
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -9304,24 +9304,16 @@ GeneralParser<ParseHandler, CharT>::arra
                                          reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
                                                               JSMSG_BRACKET_OPENED, begin));
     }
 
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
-static JSAtom*
-DoubleToAtom(JSContext* cx, double value)
-{
-    // This is safe because doubles can not be moved.
-    Value tmp = DoubleValue(value);
-    return ToAtom<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp));
-}
-
 template <class ParseHandler, typename CharT>
 typename ParseHandler::Node
 GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
                                                  const Maybe<DeclarationKind>& maybeDecl,
                                                  Node propList,
                                                  PropertyType* propType,
                                                  MutableHandleAtom propAtom)
 {
@@ -9369,17 +9361,17 @@ GeneralParser<ParseHandler, CharT>::prop
         if (!tokenStream.getToken(&ltok))
             return null();
     }
 
     propAtom.set(nullptr);
     Node propName;
     switch (ltok) {
       case TokenKind::Number:
-        propAtom.set(DoubleToAtom(context, anyChars.currentToken().number()));
+        propAtom.set(NumberToAtom(context, anyChars.currentToken().number()));
         if (!propAtom.get())
             return null();
         propName = newNumber(anyChars.currentToken());
         if (!propName)
             return null();
         break;
 
       case TokenKind::String: {
@@ -9433,27 +9425,27 @@ GeneralParser<ParseHandler, CharT>::prop
         }
         if (tt == TokenKind::String) {
             tokenStream.consumeKnownToken(TokenKind::String);
 
             propAtom.set(anyChars.currentToken().atom());
 
             uint32_t index;
             if (propAtom->isIndex(&index)) {
-                propAtom.set(DoubleToAtom(context, index));
+                propAtom.set(NumberToAtom(context, index));
                 if (!propAtom.get())
                     return null();
                 return handler.newNumber(index, NoDecimal, pos());
             }
             return stringLiteral();
         }
         if (tt == TokenKind::Number) {
             tokenStream.consumeKnownToken(TokenKind::Number);
 
-            propAtom.set(DoubleToAtom(context, anyChars.currentToken().number()));
+            propAtom.set(NumberToAtom(context, anyChars.currentToken().number()));
             if (!propAtom.get())
                 return null();
             return newNumber(anyChars.currentToken());
         }
         if (tt == TokenKind::Lb) {
             tokenStream.consumeKnownToken(TokenKind::Lb);
 
             return computedPropertyName(yieldHandling, maybeDecl, propList);
--- a/js/src/fuzz-tests/moz.build
+++ b/js/src/fuzz-tests/moz.build
@@ -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/.
 
 GeckoProgram('fuzz-tests', linkage=None)
 
 UNIFIED_SOURCES += [
     'testExample.cpp',
     'tests.cpp',
+    'testStructuredCloneReader.cpp',
 ]
 
 if CONFIG['JS_BUILD_BINAST']:
     UNIFIED_SOURCES += [
         'testBinASTReader.cpp',
     ]
 
 DEFINES['EXPORT_JS_API'] = True
new file mode 100644
--- /dev/null
+++ b/js/src/fuzz-tests/testStructuredCloneReader.cpp
@@ -0,0 +1,86 @@
+/* -*- 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 "mozilla/ScopeExit.h"
+
+#include "jsapi.h"
+
+#include "fuzz-tests/tests.h"
+#include "vm/Interpreter.h"
+
+#include "vm/JSContext-inl.h"
+
+using namespace js;
+
+// These are defined and pre-initialized by the harness (in tests.cpp).
+extern JS::PersistentRootedObject gGlobal;
+extern JSContext* gCx;
+
+static int
+testStructuredCloneReaderInit(int *argc, char ***argv) {
+  return 0;
+}
+
+static int
+testStructuredCloneReaderFuzz(const uint8_t* buf, size_t size) {
+    auto gcGuard = mozilla::MakeScopeExit([&] {
+        JS::PrepareForFullGC(gCx);
+        JS::GCForReason(gCx, GC_NORMAL, JS::gcreason::API);
+    });
+
+    if (!size) return 0;
+
+    // Make sure to pad the buffer to a multiple of kSegmentAlignment
+    const size_t kSegmentAlignment = 8;
+    size_t buf_size = JS_ROUNDUP(size, kSegmentAlignment);
+
+    auto clonebuf = MakeUnique<JSStructuredCloneData>(0, 0, buf_size);
+    if (!clonebuf || !clonebuf->Init(buf_size, buf_size)) {
+        ReportOutOfMemory(gCx);
+        return 0;
+    }
+
+    // Initialize with zeros, including padding, then copy buffer
+    memset(clonebuf->Start(), '\0', buf_size);
+    js_memcpy(clonebuf->Start(), buf, size);
+
+    JS::StructuredCloneScope scope = JS::StructuredCloneScope::DifferentProcess;
+
+    RootedValue deserialized(gCx);
+    if (!JS_ReadStructuredClone(gCx, *clonebuf,
+    			JS_STRUCTURED_CLONE_VERSION,
+    			scope,
+    			&deserialized, nullptr, nullptr))
+    {
+        return 0;
+    }
+
+    /* If we succeeded in deserializing, we should try to reserialize the data.
+       This has two main advantages:
+
+       1) It tests parts of the serializer as well.
+       2) The deserialized data is actually used, making it more likely to detect
+          further memory-related problems.
+
+       Tests show that this also doesn't cause a serious performance penalty.
+    */
+    mozilla::Maybe<JSAutoStructuredCloneBuffer> clonebufOut;
+    JS::CloneDataPolicy policy;
+
+    clonebufOut.emplace(scope, nullptr, nullptr);
+    if (!clonebufOut->write(gCx, deserialized, UndefinedHandleValue, policy))
+        return 0;
+
+    return 0;
+}
+
+MOZ_FUZZING_INTERFACE_RAW(
+    testStructuredCloneReaderInit,
+    testStructuredCloneReaderFuzz,
+    StructuredCloneReader
+);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1448582-1.js
@@ -0,0 +1,21 @@
+// Overview:
+// - The outer function is an IIFE which gets marked as a singleton.
+// - The |o[index]| inner function is then also marked as a singleton.
+// - The |o[index]| inner function has a dynamic name from a computed property name.
+// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
+//
+// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
+// function which triggered an assertion in js::SetFunctionNameIfNoOwnName().
+
+(function(index) {
+    var o = {
+        [index]: function() {}
+    };
+
+    // Reinvoke the IIFE through |Function.prototype.caller|.
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1448582-2.js
@@ -0,0 +1,25 @@
+// Overview:
+// - The outer function is an IIFE which gets marked as a singleton.
+// - The |o[index]| inner function is then also marked as a singleton.
+// - The |o[index]| inner function has a dynamic name from a computed property name.
+// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
+//
+// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
+// function which triggered an assertion in js::SetFunctionNameIfNoOwnName().
+
+(function(index) {
+    var o = {
+        [index]: function() {}
+    };
+
+    // Accessing |.name| sets the resolved-name flag, which triggered yet
+    // another assertion when compared to bug1448582-1.js
+    assertEq(o[index].name, String(index));
+
+    // Reinvoke the IIFE through |Function.prototype.caller|.
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1448582-3.js
@@ -0,0 +1,22 @@
+// Overview:
+// - The outer function is an IIFE which gets marked as a singleton.
+// - The |fn| inner function is then also marked as a singleton.
+// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
+//
+// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
+// function.
+
+(function(index) {
+    var fn = function() {};
+
+    // Accessing |.name| sets the resolved-name flag, which should not be
+    // copied over to the function clone.
+    assertEq(fn.name, "fn");
+
+    // Reinvoke the IIFE through |Function.prototype.caller|.
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1448582-4.js
@@ -0,0 +1,22 @@
+// Overview:
+// - The outer function is an IIFE which gets marked as a singleton.
+// - The |fn| inner function is then also marked as a singleton.
+// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
+//
+// When we reinvoke outer, we end up cloning a previously reused, i.e. non-cloned,
+// function.
+
+(function(index) {
+    var fn = function(a) {};
+
+    // Accessing |.length| sets the resolved-length flag, which should not be
+    // copied over to the function clone.
+    assertEq(fn.length, 1);
+
+    // Reinvoke the IIFE through |Function.prototype.caller|.
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1448582-5.js
@@ -0,0 +1,133 @@
+// Repeat 1448582-{1,3,4}.js for classes.
+
+(function(index) {
+    // Does not assert.
+    var c = class { constructor(){} };
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+(function(index) {
+    var c = class { constructor(){} };
+
+    // Accessing |.name| sets the resolved-name flag, which should not be
+    // copied over to the function clone.
+    assertEq(c.name, "c");
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+(function(index) {
+    var c = class { constructor(a){} };
+
+    // Accessing |.length| sets the resolved-length flag, which should not be
+    // copied over to the function clone.
+    assertEq(c.length, 1);
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+
+// Repeat 1448582-{3,4}.js for generator functions.
+
+(function(index) {
+    function* f() {}
+
+    // Accessing |.name| sets the resolved-name flag, which should not be
+    // copied over to the function clone.
+    assertEq(f.name, "f");
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+(function(index) {
+    function* f(a) {}
+
+    // Accessing |.length| sets the resolved-length flag, which should not be
+    // copied over to the function clone.
+    assertEq(f.length, 1);
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+
+// Repeat 1448582-{3,4}.js for async functions.
+
+(function(index) {
+    async function f() {}
+
+    // Accessing |.name| sets the resolved-name flag, which should not be
+    // copied over to the function clone.
+    assertEq(f.name, "f");
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+(function(index) {
+    async function f(a) {}
+
+    // Accessing |.length| sets the resolved-length flag, which should not be
+    // copied over to the function clone.
+    assertEq(f.length, 1);
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+
+// Repeat 1448582-{3,4}.js for async generator functions.
+
+(function(index) {
+    async function* f() {}
+
+    // Accessing |.name| sets the resolved-name flag, which should not be
+    // copied over to the function clone.
+    assertEq(f.name, "f");
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
+
+(function(index) {
+    async function* f(a) {}
+
+    // Accessing |.length| sets the resolved-length flag, which should not be
+    // copied over to the function clone.
+    assertEq(f.length, 1);
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1448582-6.js
@@ -0,0 +1,27 @@
+// Overview:
+// - The outer function is an IIFE which gets marked as a singleton.
+// - The |o[index]| inner function is then also marked as a singleton.
+// - The |o[index]| inner function has a dynamic name from a computed property name.
+// - The |self| inner function uses |Function.prototype.caller| to reinvoke the outer function.
+
+(function(index) {
+    var o = {
+        [index]: class {
+            constructor() {}
+
+            // Prevent adding an inferred name at index = 1 by creating a
+            // static method named "name".
+            static [(index === 0 ? "not-name" : "name")]() {}
+        }
+    }
+
+    // At index = 0 the class will get the inferred name "0".
+    // At index = 1 the class should have no inferred name.
+    assertEq(displayName(o[index]), index === 0 ? "0" : "");
+
+    if (index === 0) {
+        (function self() {
+            self.caller(1);
+        })();
+    }
+})(0);
--- a/js/src/jit-test/tests/basic/object-assign-unboxed.js
+++ b/js/src/jit-test/tests/basic/object-assign-unboxed.js
@@ -5,17 +5,18 @@ function Unboxed() {
     this.b = true;
 }
 
 function tryCreateUnboxedObject() {
     var obj;
     for (var i = 0; i < 1000; ++i) {
         obj = new Unboxed();
     }
-
+    if (unboxedObjectsEnabled())
+        assertEq(isUnboxedObject(obj), true);
     return obj;
 }
 
 function basic() {
     var unboxed = tryCreateUnboxedObject();
 
     var target = {};
     Object.assign(target, unboxed);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/object-rest-unboxed.js
@@ -0,0 +1,44 @@
+load(libdir + "asserts.js");
+
+function Unboxed() {
+    this.a = 0;
+    this.b = true;
+}
+
+function tryCreateUnboxedObject() {
+    var obj;
+    for (var i = 0; i < 1000; ++i) {
+        obj = new Unboxed();
+    }
+    if (unboxedObjectsEnabled())
+        assertEq(isUnboxedObject(obj), true);
+    return obj;
+}
+
+function basic() {
+    var unboxed = tryCreateUnboxedObject();
+
+    var {...target} = unboxed;
+    assertDeepEq(target, {a: 0, b: true});
+
+    var {a, c, ...target} = unboxed;
+    assertDeepEq(a, 0);
+    assertDeepEq(c, undefined);
+    assertDeepEq(target, {b: true});
+}
+
+function expando() {
+    var unboxed = tryCreateUnboxedObject();
+    unboxed.c = 3.5;
+
+    var {...target} = unboxed;
+    assertDeepEq(target, {a: 0, b: true, c: 3.5});
+
+    var {a, d, ...target} = unboxed;
+    assertDeepEq(a, 0);
+    assertDeepEq(d, undefined);
+    assertDeepEq(target, {b: true, c: 3.5});
+}
+
+basic();
+expando();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/object-rest.js
@@ -0,0 +1,90 @@
+function test() {
+    var from, to;
+
+    // From values.
+    from = {x: 1, y: 2};
+    ({...to} = from);
+    assertEq(to.y, 2);
+
+    var z;
+    from = {x: 1, y: 2};
+    ({x: z, ...to} = from);
+    assertEq(z, 1);
+    assertEq(to.y, 2);
+
+    // From getter.
+    var c = 7;
+    from = {x: 1, get y() { return ++c; }};
+    ({...to} = from);
+    assertEq(c, 8);
+    assertEq(to.y, 8);
+
+    from = {x: 1, get y() { return ++c; }};
+    ({y: z, ...to} = from);
+    assertEq(c, 9);
+    assertEq(z, 9);
+    assertEq(to.y, undefined);
+
+    // Array with dense elements.
+    from = [1, 2, 3];
+    ({...to} = from);
+    assertEq(to[2], 3);
+    assertEq("length" in to, false);
+
+    from = [1, 2, 3];
+    ({2: z, ...to} = from);
+    assertEq(z, 3);
+    assertEq(to[2], undefined);
+    assertEq(to[0], 1);
+    assertEq("length" in to, false);
+
+    // Object with sparse elements and symbols.
+    from = {x: 1, 1234567: 2, 1234560: 3, [Symbol.iterator]: 5, z: 3};
+    ({...to} = from);
+    assertEq(to[1234567], 2);
+    assertEq(Object.keys(to).toString(), "1234560,1234567,x,z");
+    assertEq(to[Symbol.iterator], 5);
+
+    from = {x: 1, 1234567: 2, 1234560: 3, [Symbol.iterator]: 5, z: 3};
+    ({[Symbol.iterator]: z, ...to} = from);
+    assertEq(to[1234567], 2);
+    assertEq(Object.keys(to).toString(), "1234560,1234567,x,z");
+    assertEq(to[Symbol.iterator], undefined);
+    assertEq(z, 5);
+
+    // Typed array.
+    from = new Int32Array([1, 2, 3]);
+    ({...to} = from);
+    assertEq(to[1], 2);
+
+    from = new Int32Array([1, 2, 3]);
+    ({1: z, ...to} = from);
+    assertEq(z, 2);
+    assertEq(to[1], undefined);
+    assertEq(to[2], 3);
+
+    // Primitive string.
+    from = "foo";
+    ({...to} = from);
+    assertEq(to[0], "f");
+
+    from = "foo";
+    ({0: z, ...to} = from);
+    assertEq(z, "f");
+    assertEq(to[0], undefined);
+    assertEq(to[1], "o");
+
+    // String object.
+    from = new String("bar");
+    ({...to} = from);
+    assertEq(to[2], "r");
+
+    from = new String("bar");
+    ({1: z, ...to} = from);
+    assertEq(z, "a");
+    assertEq(to[1], undefined);
+    assertEq(to[2], "r");
+}
+test();
+test();
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/object-spread-unboxed.js
@@ -0,0 +1,40 @@
+load(libdir + "asserts.js");
+
+function Unboxed() {
+    this.a = 0;
+    this.b = true;
+}
+
+function tryCreateUnboxedObject() {
+    var obj;
+    for (var i = 0; i < 1000; ++i) {
+        obj = new Unboxed();
+    }
+    if (unboxedObjectsEnabled())
+        assertEq(isUnboxedObject(obj), true);
+    return obj;
+}
+
+function basic() {
+    var unboxed = tryCreateUnboxedObject();
+
+    var target = {...unboxed};
+    assertDeepEq(target, {a: 0, b: true});
+
+    target = {a: 1, c: 3, ...unboxed};
+    assertDeepEq(target, {a: 0, c: 3, b: true});
+}
+
+function expando() {
+    var unboxed = tryCreateUnboxedObject();
+    unboxed.c = 3.5;
+
+    var target = {...unboxed};
+    assertDeepEq(target, {a: 0, b: true, c: 3.5});
+
+    target = {a: 1, d: 3, ...unboxed};
+    assertDeepEq(target, {a: 0, d: 3, b: true, c: 3.5});
+}
+
+basic();
+expando();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/object-spread.js
@@ -0,0 +1,49 @@
+function test() {
+    var from, to;
+
+    // From values.
+    from = {x: 1, y: 2};
+    to = {...from};
+    assertEq(to.y, 2);
+    to = {...from, ...from};
+    assertEq(to.y, 2);
+
+    // From getter.
+    var c = 7;
+    from = {x: 1, get y() { return ++c; }};
+    to = {...from};
+    assertEq(to.y, 8);
+    to = {...from, ...from};
+    assertEq(to.y, 10);
+
+    // Array with dense elements.
+    from = [1, 2, 3];
+    to = {...from};
+    assertEq(to[2], 3);
+    assertEq("length" in to, false);
+
+    // Object with sparse elements and symbols.
+    from = {x: 1, 1234567: 2, 1234560: 3, [Symbol.iterator]: 5, z: 3};
+    to = {...from};
+    assertEq(to[1234567], 2);
+    assertEq(Object.keys(to).toString(), "1234560,1234567,x,z");
+    assertEq(to[Symbol.iterator], 5);
+
+    // Typed array.
+    from = new Int32Array([1, 2, 3]);
+    to = {...from};
+    assertEq(to[1], 2);
+
+    // Primitive string.
+    from = "foo";
+    to = {...from};
+    assertEq(to[0], "f");
+
+    // String object.
+    from = new String("bar");
+    to = {...from};
+    assertEq(to[2], "r");
+}
+test();
+test();
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug1449153.js
@@ -0,0 +1,35 @@
+// Test performing GetModuleNamespace on an errored module.
+
+class MyError {}
+
+function assertThrowsMyError(f)
+{
+    let caught = false;
+    try {
+        f();
+    } catch (e) {
+        caught = true;
+        assertEq(e.constructor, MyError);
+    }
+    assertEq(caught, true);
+}
+
+let moduleRepo = {};
+setModuleResolveHook(function(module, specifier) {
+    return moduleRepo[specifier];
+});
+
+moduleRepo["a"] = parseModule(`
+    throw new MyError();
+`);
+
+let c = moduleRepo["c"] = parseModule(`
+    import "a";
+`);
+c.declarationInstantiation();
+assertThrowsMyError(() => c.evaluation());
+
+let b = moduleRepo['b'] = parseModule(`
+    import * as ns0 from 'a'
+`);
+assertThrowsMyError(() => b.declarationInstantiation());
--- a/js/src/jit-test/tests/wasm/regress/baseline-getglobal-scratch.js
+++ b/js/src/jit-test/tests/wasm/regress/baseline-getglobal-scratch.js
@@ -27,9 +27,32 @@ new WebAssembly.Module(wasmTextToBinary(
         get_global $g
         get_global $g
         get_global $g
         get_global $g
         get_global $g
         unreachable
     )
 )
-`))
+`));
+
+new WebAssembly.Module(wasmTextToBinary(`
+(module
+    (global $g (mut i32) (i32.const 42))
+    (func (param $i i32)
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_global $g
+        get_local $i
+        set_global $g
+        unreachable
+    )
+)
+`));
--- a/js/src/jit/AliasAnalysisShared.cpp
+++ b/js/src/jit/AliasAnalysisShared.cpp
@@ -118,18 +118,16 @@ GetObject(const MDefinition* ins)
       case MDefinition::Opcode::LoadElementHole:
       case MDefinition::Opcode::TypedArrayElements:
       case MDefinition::Opcode::TypedObjectElements:
       case MDefinition::Opcode::CopyLexicalEnvironmentObject:
       case MDefinition::Opcode::IsPackedArray:
         object = ins->getOperand(0);
         break;
       case MDefinition::Opcode::GetPropertyCache:
-      case MDefinition::Opcode::LoadTypedArrayElementStatic:
-      case MDefinition::Opcode::StoreTypedArrayElementStatic:
       case MDefinition::Opcode::GetDOMProperty:
       case MDefinition::Opcode::GetDOMMember:
       case MDefinition::Opcode::Call:
       case MDefinition::Opcode::Compare:
       case MDefinition::Opcode::GetArgumentsObjectArg:
       case MDefinition::Opcode::SetArgumentsObjectArg:
       case MDefinition::Opcode::GetFrameArgument:
       case MDefinition::Opcode::SetFrameArgument:
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -1375,19 +1375,21 @@ BaselineCacheIRCompiler::emitStoreDenseE
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     // Load obj->elements in scratch.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
 
-    // Bounds check.
+    // Bounds check. Unfortunately we don't have more registers available on
+    // x86, so use InvalidReg and emit slightly slower code on x86.
+    Register spectreTemp = InvalidReg;
     Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
+    masm.spectreBoundsCheck32(index, initLength, spectreTemp, failure->label());
 
     // Hole check.
     BaseObjectElementIndex element(scratch, index);
     masm.branchTestMagic(Assembler::Equal, element, failure->label());
 
     // Perform a single test to see if we either need to convert double
     // elements, clone the copy on write elements in the object or fail
     // due to a frozen element.
@@ -1466,28 +1468,40 @@ BaselineCacheIRCompiler::emitStoreDenseE
     Address elementsFlags(scratch, ObjectElements::offsetOfFlags());
 
     // Check for copy-on-write or frozen elements.
     masm.branchTest32(Assembler::NonZero, elementsFlags,
                       Imm32(ObjectElements::COPY_ON_WRITE |
                             ObjectElements::FROZEN),
                       failure->label());
 
+    // We don't have enough registers on x86 so use InvalidReg. This will emit
+    // slightly less efficient code on x86.
+    Register spectreTemp = InvalidReg;
+
     if (handleAdd) {
-        // Fail if index > initLength.
-        masm.branch32(Assembler::Below, initLength, index, failure->label());
+        // Bounds check.
+        Label capacityOk, outOfBounds;
+        masm.spectreBoundsCheck32(index, initLength, spectreTemp, &outOfBounds);
+        masm.jump(&capacityOk);
+
+        // If we're out-of-bounds, only handle the index == initLength case.
+        masm.bind(&outOfBounds);
+        masm.branch32(Assembler::NotEqual, initLength, index, failure->label());
 
         // If index < capacity, we can add a dense element inline. If not we
         // need to allocate more elements.
-        Label capacityOk;
+        Label allocElement;
         Address capacity(scratch, ObjectElements::offsetOfCapacity());
-        masm.branch32(Assembler::Above, capacity, index, &capacityOk);
+        masm.spectreBoundsCheck32(index, capacity, spectreTemp, &allocElement);
+        masm.jump(&capacityOk);
 
         // Check for non-writable array length. We only have to do this if
         // index >= capacity.
+        masm.bind(&allocElement);
         masm.branchTest32(Assembler::NonZero, elementsFlags,
                           Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
                           failure->label());
 
         LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
         save.takeUnchecked(scratch);
         masm.PushRegsInMask(save);
 
@@ -1505,17 +1519,17 @@ BaselineCacheIRCompiler::emitStoreDenseE
         masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
 
         masm.bind(&capacityOk);
 
         // We increment initLength after the callTypeUpdateIC call, to ensure
         // the type update code doesn't read uninitialized memory.
     } else {
         // Fail if index >= initLength.
-        masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
+        masm.spectreBoundsCheck32(index, initLength, spectreTemp, failure->label());
     }
 
     // Check if we have to convert a double element.
     Label noConversion;
     masm.branchTest32(Assembler::Zero, elementsFlags,
                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
                       &noConversion);
 
@@ -1590,39 +1604,41 @@ BaselineCacheIRCompiler::emitArrayPush()
     AutoScratchRegister scratchLength(allocator, masm);
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     // Load obj->elements in scratch.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
-    masm.load32(Address(scratch, ObjectElements::offsetOfLength()), scratchLength);
-
-    BaseObjectElementIndex element(scratch, scratchLength);
-    Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
+
+    Address elementsInitLength(scratch, ObjectElements::offsetOfInitializedLength());
+    Address elementsLength(scratch, ObjectElements::offsetOfLength());
     Address elementsFlags(scratch, ObjectElements::offsetOfFlags());
 
     // Check for copy-on-write or frozen elements.
     masm.branchTest32(Assembler::NonZero, elementsFlags,
                       Imm32(ObjectElements::COPY_ON_WRITE |
                             ObjectElements::FROZEN),
                       failure->label());
 
     // Fail if length != initLength.
-    masm.branch32(Assembler::NotEqual, initLength, scratchLength, failure->label());
+    masm.load32(elementsInitLength, scratchLength);
+    masm.branch32(Assembler::NotEqual, elementsLength, scratchLength, failure->label());
 
     // If scratchLength < capacity, we can add a dense element inline. If not we
     // need to allocate more elements.
-    Label capacityOk;
+    Label capacityOk, allocElement;
     Address capacity(scratch, ObjectElements::offsetOfCapacity());
-    masm.branch32(Assembler::Above, capacity, scratchLength, &capacityOk);
+    masm.spectreBoundsCheck32(scratchLength, capacity, InvalidReg, &allocElement);
+    masm.jump(&capacityOk);
 
     // Check for non-writable array length. We only have to do this if
     // index >= capacity.
+    masm.bind(&allocElement);
     masm.branchTest32(Assembler::NonZero, elementsFlags,
                       Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
                       failure->label());
 
     LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
     save.takeUnchecked(scratch);
     masm.PushRegsInMask(save);
 
@@ -1667,22 +1683,22 @@ BaselineCacheIRCompiler::emitArrayPush()
     saveRegs.add(val);
     if (!callTypeUpdateIC(obj, val, scratch, saveRegs))
         return false;
 
     // Reload obj->elements as callTypeUpdateIC used the scratch register.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
 
     // Increment initLength and length.
-    Address length(scratch, ObjectElements::offsetOfLength());
-    masm.add32(Imm32(1), initLength);
-    masm.load32(length, scratchLength);
-    masm.add32(Imm32(1), length);
+    masm.add32(Imm32(1), elementsInitLength);
+    masm.load32(elementsLength, scratchLength);
+    masm.add32(Imm32(1), elementsLength);
 
     // Store the value.
+    BaseObjectElementIndex element(scratch, scratchLength);
     masm.storeValue(val, element);
     emitPostBarrierElement(obj, val, scratch, scratchLength);
 
     // Return value is new length.
     masm.add32(Imm32(1), scratchLength);
     masm.tagValue(JSVAL_TYPE_INT32, scratchLength, val);
 
     return true;
@@ -1703,17 +1719,21 @@ BaselineCacheIRCompiler::emitStoreTypedE
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     // Bounds check.
     Label done;
     LoadTypedThingLength(masm, layout, obj, scratch1);
-    masm.branch32(Assembler::BelowOrEqual, scratch1, index, handleOOB ? &done : failure->label());
+
+    // Unfortunately we don't have more registers available on x86, so use
+    // InvalidReg and emit slightly slower code on x86.
+    Register spectreTemp = InvalidReg;
+    masm.spectreBoundsCheck32(index, scratch1, spectreTemp, handleOOB ? &done : failure->label());
 
     // Load the elements vector.
     LoadTypedThingData(masm, layout, obj, scratch1);
 
     BaseIndex dest(scratch1, index, ScaleFromElemWidth(Scalar::byteSize(type)));
 
     // Use ICStubReg as second scratch register. TODO: consider doing the RHS
     // type check/conversion as a separate IR instruction so we can simplify
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6853,26 +6853,34 @@ CodeGenerator::visitArrowNewTarget(LArro
 
 void
 CodeGenerator::visitArrayLength(LArrayLength* lir)
 {
     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
     masm.load32(length, ToRegister(lir->output()));
 }
 
+static void
+SetLengthFromIndex(MacroAssembler& masm, const LAllocation* index, const Address& length)
+{
+    if (index->isConstant()) {
+        masm.store32(Imm32(ToInt32(index) + 1), length);
+    } else {
+        Register newLength = ToRegister(index);
+        masm.add32(Imm32(1), newLength);
+        masm.store32(newLength, length);
+        masm.sub32(Imm32(1), newLength);
+    }
+}
+
 void
 CodeGenerator::visitSetArrayLength(LSetArrayLength* lir)
 {
     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
-    RegisterOrInt32Constant newLength = ToRegisterOrInt32Constant(lir->index());
-
-    masm.inc32(&newLength);
-    masm.store32(newLength, length);
-    // Restore register value if it is used/captured after.
-    masm.dec32(&newLength);
+    SetLengthFromIndex(masm, lir->index(), length);
 }
 
 template <class OrderedHashTable>
 static void
 RangeFront(MacroAssembler&, Register, Register, Register);
 
 template <>
 void
@@ -8893,22 +8901,17 @@ CodeGenerator::visitInitializedLength(LI
     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
     masm.load32(initLength, ToRegister(lir->output()));
 }
 
 void
 CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
 {
     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
-    RegisterOrInt32Constant index = ToRegisterOrInt32Constant(lir->index());
-
-    masm.inc32(&index);
-    masm.store32(index, initLength);
-    // Restore register value if it is used/captured after.
-    masm.dec32(&index);
+    SetLengthFromIndex(masm, lir->index(), initLength);
 }
 
 void
 CodeGenerator::visitNotO(LNotO* lir)
 {
     MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
                "This should be constant-folded if the object can't emulate undefined.");
 
@@ -9218,28 +9221,28 @@ CodeGenerator::emitStoreElementHoleT(T* 
     static_assert(std::is_same<T, LStoreElementHoleT>::value || std::is_same<T, LFallibleStoreElementT>::value,
                   "emitStoreElementHoleT called with unexpected argument type");
 
     OutOfLineStoreElementHole* ool =
         new(alloc()) OutOfLineStoreElementHole(lir, current->mir()->strict());
     addOutOfLineCode(ool, lir->mir());
 
     Register elements = ToRegister(lir->elements());
-    const LAllocation* index = lir->index();
-    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
+    Register index = ToRegister(lir->index());
+    Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
 
     Address initLength(elements, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
+    masm.spectreBoundsCheck32(index, initLength, spectreTemp, ool->entry());
 
     if (lir->mir()->needsBarrier())
-        emitPreBarrier(elements, index, 0);
+        emitPreBarrier(elements, lir->index(), 0);
 
     masm.bind(ool->rejoinStore());
     emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
-                          elements, index, 0);
+                          elements, lir->index(), 0);
 
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
 {
     emitStoreElementHoleT(lir);
@@ -9251,31 +9254,28 @@ CodeGenerator::emitStoreElementHoleV(T* 
     static_assert(std::is_same<T, LStoreElementHoleV>::value || std::is_same<T, LFallibleStoreElementV>::value,
                   "emitStoreElementHoleV called with unexpected parameter type");
 
     OutOfLineStoreElementHole* ool =
         new(alloc()) OutOfLineStoreElementHole(lir, current->mir()->strict());
     addOutOfLineCode(ool, lir->mir());
 
     Register elements = ToRegister(lir->elements());
-    const LAllocation* index = lir->index();
+    Register index = ToRegister(lir->index());
     const ValueOperand value = ToValue(lir, T::Value);
-    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
+    Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
 
     Address initLength(elements, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
+    masm.spectreBoundsCheck32(index, initLength, spectreTemp, ool->entry());
 
     if (lir->mir()->needsBarrier())
-        emitPreBarrier(elements, index, 0);
+        emitPreBarrier(elements, lir->index(), 0);
 
     masm.bind(ool->rejoinStore());
-    if (index->isConstant())
-        masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
-    else
-        masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
+    masm.storeValue(value, BaseIndex(elements, index, TimesEight));
 
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV* lir)
 {
     emitStoreElementHoleV(lir);
@@ -9357,84 +9357,91 @@ static const VMFunction SetDenseElementI
 void
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
 {
     Register object, elements;
     LInstruction* ins = ool->ins();
     const LAllocation* index;
     MIRType valueType;
     ConstantOrRegister value;
+    Register spectreTemp;
 
     if (ins->isStoreElementHoleV()) {
         LStoreElementHoleV* store = ins->toStoreElementHoleV();
         object = ToRegister(store->object());
         elements = ToRegister(store->elements());
         index = store->index();
         valueType = store->mir()->value()->type();
         value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
+        spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
     } else if (ins->isFallibleStoreElementV()) {
         LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
         object = ToRegister(store->object());
         elements = ToRegister(store->elements());
         index = store->index();
         valueType = store->mir()->value()->type();
         value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
+        spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
     } else if (ins->isStoreElementHoleT()) {
         LStoreElementHoleT* store = ins->toStoreElementHoleT();
         object = ToRegister(store->object());
         elements = ToRegister(store->elements());
         index = store->index();
         valueType = store->mir()->value()->type();
         if (store->value()->isConstant())
             value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
         else
             value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
+        spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
     } else { // ins->isFallibleStoreElementT()
         LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
         object = ToRegister(store->object());
         elements = ToRegister(store->elements());
         index = store->index();
         valueType = store->mir()->value()->type();
         if (store->value()->isConstant())
             value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
         else
             value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
-    }
-
-    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
+        spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
+    }
+
+    Register indexReg = ToRegister(index);
 
     // If index == initializedLength, try to bump the initialized length inline.
     // If index > initializedLength, call a stub. Note that this relies on the
     // condition flags sticking from the incoming branch.
+    // Also note: this branch does not need Spectre mitigations, doing that for
+    // the capacity check below is sufficient.
     Label callStub;
 #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     // Had to reimplement for MIPS because there are no flags.
     Address initLength(elements, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
+    masm.branch32(Assembler::NotEqual, initLength, indexReg, &callStub);
 #else
     masm.j(Assembler::NotEqual, &callStub);
 #endif
 
     // Check array capacity.
-    masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
-                  key, &callStub);
+    masm.spectreBoundsCheck32(indexReg, Address(elements, ObjectElements::offsetOfCapacity()),
+                              spectreTemp, &callStub);
 
     // Update initialized length. The capacity guard above ensures this won't overflow,
     // due to MAX_DENSE_ELEMENTS_COUNT.
-    masm.inc32(&key);
-    masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
+    masm.add32(Imm32(1), indexReg);
+    masm.store32(indexReg, Address(elements, ObjectElements::offsetOfInitializedLength()));
 
     // Update length if length < initializedLength.
     Label dontUpdate;
     masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
-                  key, &dontUpdate);
-    masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
+                  indexReg, &dontUpdate);
+    masm.store32(indexReg, Address(elements, ObjectElements::offsetOfLength()));
     masm.bind(&dontUpdate);
 
-    masm.dec32(&key);
+    masm.sub32(Imm32(1), indexReg);
 
     if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
         valueType != MIRType::Double)
     {
         // The inline path for StoreElementHoleT and FallibleStoreElementT does not always store
         // the type tag, so we do the store on the OOL path. We use MIRType::None for the element
         // type so that storeElementTyped will always store the type tag.
         if (ins->isStoreElementHoleT()) {
@@ -9555,23 +9562,23 @@ CodeGenerator::emitArrayPopShift(LInstru
     } else {
         MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
         ool = oolCallVM(ArrayShiftDenseInfo, lir, ArgList(obj), StoreValueTo(out));
     }
 
     // VM call if a write barrier is necessary.
     masm.branchTestNeedsIncrementalBarrier(Assembler::NonZero, ool->entry());
 
-    // Load elements and length, and VM call if length != initializedLength.
-    RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp);
+    // Load elements and initializedLength, and VM call if
+    // length != initializedLength.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
-    masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
-
-    Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
+    masm.load32(Address(elementsTemp, ObjectElements::offsetOfInitializedLength()), lengthTemp);
+
+    Address lengthAddr(elementsTemp, ObjectElements::offsetOfLength());
+    masm.branch32(Assembler::NotEqual, lengthAddr, lengthTemp, ool->entry());
 
     // Test for length != 0. On zero length either take a VM call or generate
     // an undefined value, depending on whether the call is known to produce
     // undefined.
     Label done;
     if (mir->maybeUndefined()) {
         Label notEmpty;
         masm.branchTest32(Assembler::NonZero, lengthTemp, lengthTemp, &notEmpty);
@@ -9585,17 +9592,17 @@ CodeGenerator::emitArrayPopShift(LInstru
 
         masm.moveValue(UndefinedValue(), out.valueReg());
         masm.jump(&done);
         masm.bind(&notEmpty);
     } else {
         masm.branchTest32(Assembler::Zero, lengthTemp, lengthTemp, ool->entry());
     }
 
-    masm.dec32(&key);
+    masm.sub32(Imm32(1), lengthTemp);
 
     if (mir->mode() == MArrayPopShift::Pop) {
         BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
         masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
     } else {
         MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
         Address addr(elementsTemp, 0);
         masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
@@ -9653,68 +9660,69 @@ CodeGenerator::visitArrayPopShiftT(LArra
 }
 
 typedef bool (*ArrayPushDenseFn)(JSContext*, HandleArrayObject, HandleValue, uint32_t*);
 static const VMFunction ArrayPushDenseInfo =
     FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense, "ArrayPushDense");
 
 void
 CodeGenerator::emitArrayPush(LInstruction* lir, Register obj,
-                             const ConstantOrRegister& value, Register elementsTemp, Register length)
+                             const ConstantOrRegister& value, Register elementsTemp, Register length,
+                             Register spectreTemp)
 {
     OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
 
-    RegisterOrInt32Constant key = RegisterOrInt32Constant(length);
-
     // Load elements and length.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
     masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
 
     // Guard length == initializedLength.
     Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
+    masm.branch32(Assembler::NotEqual, initLength, length, ool->entry());
 
     // Guard length < capacity.
     Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
-    masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
+    masm.spectreBoundsCheck32(length, capacity, spectreTemp, ool->entry());
 
     // Do the store.
     masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
 
-    masm.inc32(&key);
+    masm.add32(Imm32(1), length);
 
     // Update length and initialized length.
     masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
     masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
 
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGenerator::visitArrayPushV(LArrayPushV* lir)
 {
     Register obj = ToRegister(lir->object());
     Register elementsTemp = ToRegister(lir->temp());
     Register length = ToRegister(lir->output());
     ConstantOrRegister value = TypedOrValueRegister(ToValue(lir, LArrayPushV::Value));
-    emitArrayPush(lir, obj, value, elementsTemp, length);
+    Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
+    emitArrayPush(lir, obj, value, elementsTemp, length, spectreTemp);
 }
 
 void
 CodeGenerator::visitArrayPushT(LArrayPushT* lir)
 {
     Register obj = ToRegister(lir->object());
     Register elementsTemp = ToRegister(lir->temp());
     Register length = ToRegister(lir->output());
     ConstantOrRegister value;
     if (lir->value()->isConstant())
         value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
     else
         value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
-    emitArrayPush(lir, obj, value, elementsTemp, length);
+    Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
+    emitArrayPush(lir, obj, value, elementsTemp, length, spectreTemp);
 }
 
 typedef JSObject* (*ArraySliceDenseFn)(JSContext*, HandleObject, int32_t, int32_t, HandleObject);
 static const VMFunction ArraySliceDenseInfo =
     FunctionInfo<ArraySliceDenseFn>(array_slice_dense, "array_slice_dense");
 
 void
 CodeGenerator::visitArraySlice(LArraySlice* lir)
@@ -11815,52 +11823,30 @@ void
 CodeGenerator::visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole* lir)
 {
     Register elements = ToRegister(lir->elements());
     const LAllocation* value = lir->value();
 
     Scalar::Type arrayType = lir->mir()->arrayType();
     int width = Scalar::byteSize(arrayType);
 
-    const LAllocation* index = lir->index();
+    Register index = ToRegister(lir->index());
     const LAllocation* length = lir->length();
-
-    bool guardLength = true;
-    if (index->isConstant() && length->isConstant()) {
-        uint32_t idx = ToInt32(index);
-        uint32_t len = ToInt32(length);
-        if (idx >= len)
-            return;
-        guardLength = false;
-    }
+    Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
+
     Label skip;
-    if (index->isConstant()) {
-        uint32_t idx = ToInt32(index);
-        if (guardLength) {
-            if (length->isRegister())
-                masm.branch32(Assembler::BelowOrEqual, ToRegister(length), Imm32(idx), &skip);
-            else
-                masm.branch32(Assembler::BelowOrEqual, ToAddress(length), Imm32(idx), &skip);
-        }
-        Address dest(elements, idx * width);
-        StoreToTypedArray(masm, arrayType, value, dest);
-    } else {
-        Register idxReg = ToRegister(index);
-        MOZ_ASSERT(guardLength);
-        if (length->isConstant())
-            masm.branch32(Assembler::AboveOrEqual, idxReg, Imm32(ToInt32(length)), &skip);
-        else if (length->isRegister())
-            masm.branch32(Assembler::BelowOrEqual, ToRegister(length), idxReg, &skip);
-        else
-            masm.branch32(Assembler::BelowOrEqual, ToAddress(length), idxReg, &skip);
-        BaseIndex dest(elements, ToRegister(index), ScaleFromElemWidth(width));
-        StoreToTypedArray(masm, arrayType, value, dest);
-    }
-    if (guardLength)
-        masm.bind(&skip);
+    if (length->isRegister())
+        masm.spectreBoundsCheck32(index, ToRegister(length), spectreTemp, &skip);
+    else
+        masm.spectreBoundsCheck32(index, ToAddress(length), spectreTemp, &skip);
+
+    BaseIndex dest(elements, index, ScaleFromElemWidth(width));
+    StoreToTypedArray(masm, arrayType, value, dest);
+
+    masm.bind(&skip);
 }
 
 void
 CodeGenerator::visitAtomicIsLockFree(LAtomicIsLockFree* lir)
 {
     Register value = ToRegister(lir->value());
     Register output = ToRegister(lir->output());
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -158,17 +158,18 @@ class CodeGenerator final : public CodeG
     template<typename T> void emitLoadElementT(LLoadElementT* lir, const T& source);
 
     template <typename T> void emitStoreElementHoleT(T* lir);
     template <typename T> void emitStoreElementHoleV(T* lir);
 
     void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
                            Register elementsTemp, Register lengthTemp, TypedOrValueRegister out);
     void emitArrayPush(LInstruction* lir, Register obj,
-                       const ConstantOrRegister& value, Register elementsTemp, Register length);
+                       const ConstantOrRegister& value, Register elementsTemp, Register length,
+                       Register spectreTemp);
 
     void emitRest(LInstruction* lir, Register array, Register numActuals,
                   Register temp0, Register temp1, unsigned numFormals,
                   JSObject* templateObject, bool saveAndRestore, Register resultreg);
     void emitInstanceOf(LInstruction* ins, JSObject* prototypeObject);
 
     enum CallableOrConstructor {
         Callable,
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1676,17 +1676,17 @@ TypeAnalyzer::adjustPhiInputs(MPhi* phi)
 bool
 TypeAnalyzer::adjustInputs(MDefinition* def)
 {
     // Definitions such as MPhi have no type policy.
     if (!def->isInstruction())
         return true;
 
     MInstruction* ins = def->toInstruction();
-    TypePolicy* policy = ins->typePolicy();
+    const TypePolicy* policy = ins->typePolicy();
     if (policy && !policy->adjustInputs(alloc(), ins))
         return false;
     return true;
 }
 
 void
 TypeAnalyzer::replaceRedundantPhi(MPhi* phi)
 {
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7796,21 +7796,16 @@ IonBuilder::jsop_getelem()
         if (emitted)
             return Ok();
 
         trackOptimizationAttempt(TrackedStrategy::GetElem_Dense);
         MOZ_TRY(getElemTryDense(&emitted, obj, index));
         if (emitted)
             return Ok();
 
-        trackOptimizationAttempt(TrackedStrategy::GetElem_TypedStatic);
-        MOZ_TRY(getElemTryTypedStatic(&emitted, obj, index));
-        if (emitted)
-            return Ok();
-
         trackOptimizationAttempt(TrackedStrategy::GetElem_TypedArray);
         MOZ_TRY(getElemTryTypedArray(&emitted, obj, index));
         if (emitted)
             return Ok();
 
         trackOptimizationAttempt(TrackedStrategy::GetElem_String);
         MOZ_TRY(getElemTryString(&emitted, obj, index));
         if (emitted)
@@ -8224,112 +8219,16 @@ IonBuilder::getElemTryDense(bool* emitte
 
     MOZ_TRY(jsop_getelem_dense(obj, index));
 
     trackOptimizationSuccess();
     *emitted = true;
     return Ok();
 }
 
-AbortReasonOr<JSObject*>
-IonBuilder::getStaticTypedArrayObject(MDefinition* obj, MDefinition* index)
-{
-    Scalar::Type arrayType;
-    if (!ElementAccessIsTypedArray(constraints(), obj, index, &arrayType)) {
-        trackOptimizationOutcome(TrackedOutcome::AccessNotTypedArray);
-        return nullptr;
-    }
-
-    if (!LIRGenerator::allowStaticTypedArrayAccesses()) {
-        trackOptimizationOutcome(TrackedOutcome::Disabled);
-        return nullptr;
-    }
-
-    bool hasExtraIndexedProperty;
-    MOZ_TRY_VAR(hasExtraIndexedProperty, ElementAccessHasExtraIndexedProperty(this, obj));
-    if (hasExtraIndexedProperty) {
-        trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
-        return nullptr;
-    }
-
-    if (!obj->resultTypeSet()) {
-        trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
-        return nullptr;
-    }
-
-    JSObject* tarrObj = obj->resultTypeSet()->maybeSingleton();
-    if (!tarrObj) {
-        trackOptimizationOutcome(TrackedOutcome::NotSingleton);
-        return nullptr;
-    }
-
-    TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarrObj);
-    if (tarrKey->unknownProperties()) {
-        trackOptimizationOutcome(TrackedOutcome::UnknownProperties);
-        return nullptr;
-    }
-
-    return tarrObj;
-}
-
-AbortReasonOr<Ok>
-IonBuilder::getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index)
-{
-    MOZ_ASSERT(*emitted == false);
-
-    JSObject* tarrObj;
-    MOZ_TRY_VAR(tarrObj, getStaticTypedArrayObject(obj, index));
-    if (!tarrObj)
-        return Ok();
-
-    // LoadTypedArrayElementStatic currently treats uint32 arrays as int32.
-    Scalar::Type viewType = tarrObj->as<TypedArrayObject>().type();
-    if (viewType == Scalar::Uint32) {
-        trackOptimizationOutcome(TrackedOutcome::StaticTypedArrayUint32);
-        return Ok();
-    }
-
-    MDefinition* ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
-    if (!ptr)
-        return Ok();
-
-    // Emit LoadTypedArrayElementStatic.
-
-    if (tarrObj->is<TypedArrayObject>()) {
-        TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarrObj);
-        tarrKey->watchStateChangeForTypedArrayData(constraints());
-    }
-
-    obj->setImplicitlyUsedUnchecked();
-    index->setImplicitlyUsedUnchecked();
-
-    MLoadTypedArrayElementStatic* load = MLoadTypedArrayElementStatic::New(alloc(), tarrObj, ptr);
-    current->add(load);
-    current->push(load);
-
-    // The load is infallible if an undefined result will be coerced to the
-    // appropriate numeric type if the read is out of bounds. The truncation
-    // analysis picks up some of these cases, but is incomplete with respect
-    // to others. For now, sniff the bytecode for simple patterns following
-    // the load which guarantee a truncation or numeric conversion.
-    if (viewType == Scalar::Float32 || viewType == Scalar::Float64) {
-        jsbytecode* next = pc + JSOP_GETELEM_LENGTH;
-        if (*next == JSOP_POS)
-            load->setInfallible();
-    } else {
-        jsbytecode* next = pc + JSOP_GETELEM_LENGTH;
-        if (*next == JSOP_ZERO && *(next + JSOP_ZERO_LENGTH) == JSOP_BITOR)
-            load->setInfallible();
-    }
-
-    trackOptimizationSuccess();
-    *emitted = true;
-    return Ok();
-}
-
 AbortReasonOr<Ok>
 IonBuilder::getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index)
 {
     MOZ_ASSERT(*emitted == false);
 
     Scalar::Type arrayType;
     if (!ElementAccessIsTypedArray(constraints(), obj, index, &arrayType)) {
         trackOptimizationOutcome(TrackedOutcome::AccessNotTypedArray);
@@ -8782,60 +8681,16 @@ IonBuilder::addTypedArrayLengthAndData(M
         if (checking == DoBoundsCheck)
             *index = addBoundsCheck(*index, *length);
 
         *elements = MTypedArrayElements::New(alloc(), obj);
         current->add(*elements);
     }
 }
 
-MDefinition*
-IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition* id,
-                                                  Scalar::Type viewType)
-{
-    trackOptimizationOutcome(TrackedOutcome::StaticTypedArrayCantComputeMask);
-
-    // No shifting is necessary if the typed array has single byte elements.
-    if (TypedArrayShift(viewType) == 0)
-        return id;
-
-    // If the index is an already shifted constant, undo the shift to get the
-    // absolute offset being accessed.
-    if (MConstant* idConst = id->maybeConstantValue()) {
-        if (idConst->type() == MIRType::Int32) {
-            int32_t index = idConst->toInt32();
-            MConstant* offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType)));
-            current->add(offset);
-            return offset;
-        }
-    }
-
-    if (!id->isRsh() || id->isEffectful())
-        return nullptr;
-
-    MConstant* shiftAmount = id->toRsh()->rhs()->maybeConstantValue();
-    if (!shiftAmount || shiftAmount->type() != MIRType::Int32)
-        return nullptr;
-    if (uint32_t(shiftAmount->toInt32()) != TypedArrayShift(viewType))
-        return nullptr;
-
-    // Instead of shifting, mask off the low bits of the index so that
-    // a non-scaled access on the typed array can be performed.
-    MConstant* mask = MConstant::New(alloc(), Int32Value(~((1 << shiftAmount->toInt32()) - 1)));
-    MBitAnd* ptr = MBitAnd::New(alloc(), id->getOperand(0), mask);
-
-    ptr->infer(nullptr, nullptr);
-    MOZ_ASSERT(!ptr->isEffectful());
-
-    current->add(mask);
-    current->add(ptr);
-
-    return ptr;
-}
-
 AbortReasonOr<Ok>
 IonBuilder::jsop_getelem_typed(MDefinition* obj, MDefinition* index,
                                Scalar::Type arrayType)
 {
     TemporaryTypeSet* types = bytecodeTypes(pc);
 
     bool maybeUndefined = types->hasType(TypeSet::UndefinedType());
 
@@ -8928,21 +8783,16 @@ IonBuilder::jsop_setelem()
     if (shouldAbortOnPreliminaryGroups(object)) {
         MInstruction* ins = MCallSetElement::New(alloc(), object, index, value, IsStrictSetPC(pc));
         current->add(ins);
         current->push(value);
         return resumeAfter(ins);
     }
 
     if (!forceInlineCaches()) {
-        trackOptimizationAttempt(TrackedStrategy::SetElem_TypedStatic);
-        MOZ_TRY(setElemTryTypedStatic(&emitted, object, index, value));
-        if (emitted)
-            return Ok();
-
         trackOptimizationAttempt(TrackedStrategy::SetElem_TypedArray);
         MOZ_TRY(setElemTryTypedArray(&emitted, object, index, value));
         if (emitted)
             return Ok();
 
         trackOptimizationAttempt(TrackedStrategy::SetElem_Dense);
         SetElemICInspector icInspect(inspector->setElemICInspector(pc));
         bool writeHole = icInspect.sawOOBDenseWrite();
@@ -9070,64 +8920,16 @@ IonBuilder::setElemTryScalarElemOfTypedO
     LinearSum indexAsByteOffset(alloc());
     if (!checkTypedObjectIndexInBounds(elemSize, index, objPrediction, &indexAsByteOffset))
         return Ok();
 
     return setPropTryScalarTypedObjectValue(emitted, obj, indexAsByteOffset, elemType, value);
 }
 
 AbortReasonOr<Ok>
-IonBuilder::setElemTryTypedStatic(bool* emitted, MDefinition* object,
-                                  MDefinition* index, MDefinition* value)
-{
-    MOZ_ASSERT(*emitted == false);
-
-    JSObject* tarrObj;
-    MOZ_TRY_VAR(tarrObj, getStaticTypedArrayObject(object, index));
-    if (!tarrObj)
-        return Ok();
-
-    SharedMem<void*> viewData = tarrObj->as<TypedArrayObject>().viewDataEither();
-    if (tarrObj->zone()->group()->nursery().isInside(viewData))
-        return Ok();
-
-    Scalar::Type viewType = tarrObj->as<TypedArrayObject>().type();
-    MDefinition* ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
-    if (!ptr)
-        return Ok();
-
-    // Emit StoreTypedArrayElementStatic.
-
-    if (tarrObj->is<TypedArrayObject>()) {
-        TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarrObj);
-        tarrKey->watchStateChangeForTypedArrayData(constraints());
-    }
-
-    object->setImplicitlyUsedUnchecked();
-    index->setImplicitlyUsedUnchecked();
-
-    // Clamp value to [0, 255] for Uint8ClampedArray.
-    MDefinition* toWrite = value;
-    if (viewType == Scalar::Uint8Clamped) {
-        toWrite = MClampToUint8::New(alloc(), value);
-        current->add(toWrite->toInstruction());
-    }
-
-    MInstruction* store = MStoreTypedArrayElementStatic::New(alloc(), tarrObj, ptr, toWrite);
-    current->add(store);
-    current->push(value);
-
-    MOZ_TRY(resumeAfter(store));
-
-    trackOptimizationSuccess();
-    *emitted = true;
-    return Ok();
-}
-
-AbortReasonOr<Ok>
 IonBuilder::setElemTryTypedArray(bool* emitted, MDefinition* object,
                                  MDefinition* index, MDefinition* value)
 {
     MOZ_ASSERT(*emitted == false);
 
     Scalar::Type arrayType;
     if (!ElementAccessIsTypedArray(constraints(), object, index, &arrayType)) {
         trackOptimizationOutcome(TrackedOutcome::AccessNotTypedArray);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -204,19 +204,16 @@ class IonBuilder
     MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
     MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
     MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
     MInstruction* addSharedTypedArrayGuard(MDefinition* obj);
 
     MInstruction*
     addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers);
 
-    MDefinition* convertShiftToMaskForStaticTypedArray(MDefinition* id,
-                                                       Scalar::Type viewType);
-
     bool invalidatedIdempotentCache();
 
     bool hasStaticEnvironmentObject(JSObject** pcall);
     AbortReasonOr<Ok> loadSlot(MDefinition* obj, size_t slot, size_t nfixed, MIRType rvalType,
                                BarrierKind barrier, TemporaryTypeSet* types);
     AbortReasonOr<Ok> loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType,
                                BarrierKind barrier, TemporaryTypeSet* types);
     AbortReasonOr<Ok> storeSlot(MDefinition* obj, size_t slot, size_t nfixed, MDefinition* value,
@@ -386,25 +383,22 @@ class IonBuilder
                                              MDefinition* derivedTypeObj);
     AbortReasonOr<Ok> pushScalarLoadFromTypedObject(MDefinition* obj,
                                                     const LinearSum& byteoffset,
                                                     ScalarTypeDescr::Type type);
     AbortReasonOr<Ok> pushReferenceLoadFromTypedObject(MDefinition* typedObj,
                                                        const LinearSum& byteOffset,
                                                        ReferenceTypeDescr::Type type,
                                                        PropertyName* name);
-    AbortReasonOr<JSObject*> getStaticTypedArrayObject(MDefinition* obj, MDefinition* index);
 
     // jsop_setelem() helpers.
     AbortReasonOr<Ok> setElemTryTypedArray(bool* emitted, MDefinition* object,
                                            MDefinition* index, MDefinition* value);
     AbortReasonOr<Ok> setElemTryTypedObject(bool* emitted, MDefinition* obj,
                                             MDefinition* index, MDefinition* value);
-    AbortReasonOr<Ok> setElemTryTypedStatic(bool* emitted, MDefinition* object,
-                                            MDefinition* index, MDefinition* value);
     AbortReasonOr<Ok> initOrSetElemTryDense(bool* emitted, MDefinition* object,
                                             MDefinition* index, MDefinition* value,
                                             bool writeHole);
     AbortReasonOr<Ok> setElemTryArguments(bool* emitted, MDefinition* object);
     AbortReasonOr<Ok> initOrSetElemTryCache(bool* emitted, MDefinition* object,
                                             MDefinition* index, MDefinition* value);
     AbortReasonOr<Ok> setElemTryReferenceElemOfTypedObject(bool* emitted,
                                                            MDefinition* obj,
@@ -420,17 +414,16 @@ class IonBuilder
                                                         TypedObjectPrediction elemTypeReprs,
                                                         uint32_t elemSize);
     AbortReasonOr<Ok> initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value,
                                              bool addResumePointAndIncrementInitializedLength);
 
     // jsop_getelem() helpers.
     AbortReasonOr<Ok> getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index);
     AbortReasonOr<Ok> getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index);
-    AbortReasonOr<Ok> getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index);
     AbortReasonOr<Ok> getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index);
     AbortReasonOr<Ok> getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index);
     AbortReasonOr<Ok> getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index);
     AbortReasonOr<Ok> getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* index);
     AbortReasonOr<Ok> getElemTryArgumentsInlinedConstant(bool* emitted, MDefinition* obj,
                                                          MDefinition* index);
     AbortReasonOr<Ok> getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj,
                                                       MDefinition* index);
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -1896,125 +1896,134 @@ EmitStoreDenseElement(MacroAssembler& ma
 
 bool
 IonCacheIRCompiler::emitStoreDenseElement()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     Register index = allocator.useRegister(masm, reader.int32OperandId());
     ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
 
-    AutoScratchRegister scratch(allocator, masm);
+    AutoScratchRegister scratch1(allocator, masm);
+    AutoScratchRegister scratch2(allocator, masm);
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, failure->label());
 
     // Load obj->elements in scratch.
-    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
 
     // Bounds check.
-    Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
+    Address initLength(scratch1, ObjectElements::offsetOfInitializedLength());
+    masm.spectreBoundsCheck32(index, initLength, scratch2, failure->label());
 
     // Hole check.
-    BaseObjectElementIndex element(scratch, index);
+    BaseObjectElementIndex element(scratch1, index);
     masm.branchTestMagic(Assembler::Equal, element, failure->label());
 
     EmitPreBarrier(masm, element, MIRType::Value);
-    EmitStoreDenseElement(masm, val, scratch, element);
+    EmitStoreDenseElement(masm, val, scratch1, element);
     if (needsPostBarrier())
-        emitPostBarrierElement(obj, val, scratch, index);
+        emitPostBarrierElement(obj, val, scratch1, index);
     return true;
 }
 
 bool
 IonCacheIRCompiler::emitStoreDenseElementHole()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     Register index = allocator.useRegister(masm, reader.int32OperandId());
     ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
 
     // handleAdd boolean is only relevant for Baseline. Ion ICs can always
     // handle adds as we don't have to set any flags on the fallback stub to
     // track this.
     reader.readBool();
 
-    AutoScratchRegister scratch(allocator, masm);
+    AutoScratchRegister scratch1(allocator, masm);
+    AutoScratchRegister scratch2(allocator, masm);
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, failure->label());
 
-    // Load obj->elements in scratch.
-    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
-
-    Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
-    BaseObjectElementIndex element(scratch, index);
-
-    Label inBounds, doStore;
-    masm.branch32(Assembler::Above, initLength, index, &inBounds);
+    // Load obj->elements in scratch1.
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
+
+    Address initLength(scratch1, ObjectElements::offsetOfInitializedLength());
+    BaseObjectElementIndex element(scratch1, index);
+
+    Label inBounds, outOfBounds;
+    Register spectreTemp = scratch2;
+    masm.spectreBoundsCheck32(index, initLength, spectreTemp, &outOfBounds);
+    masm.jump(&inBounds);
+
+    masm.bind(&outOfBounds);
     masm.branch32(Assembler::NotEqual, initLength, index, failure->label());
 
     // If index < capacity, we can add a dense element inline. If not we
     // need to allocate more elements.
-    Label capacityOk;
-    Address capacity(scratch, ObjectElements::offsetOfCapacity());
-    masm.branch32(Assembler::Above, capacity, index, &capacityOk);
+    Label capacityOk, allocElement;
+    Address capacity(scratch1, ObjectElements::offsetOfCapacity());
+    masm.spectreBoundsCheck32(index, capacity, spectreTemp, &allocElement);
+    masm.jump(&capacityOk);
 
     // Check for non-writable array length. We only have to do this if
     // index >= capacity.
-    Address elementsFlags(scratch, ObjectElements::offsetOfFlags());
+    masm.bind(&allocElement);
+    Address elementsFlags(scratch1, ObjectElements::offsetOfFlags());
     masm.branchTest32(Assembler::NonZero, elementsFlags,
                       Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
                       failure->label());
 
     LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
-    save.takeUnchecked(scratch);
+    save.takeUnchecked(scratch1);
     masm.PushRegsInMask(save);
 
-    masm.setupUnalignedABICall(scratch);
-    masm.loadJSContext(scratch);
-    masm.passABIArg(scratch);
+    masm.setupUnalignedABICall(scratch1);
+    masm.loadJSContext(scratch1);
+    masm.passABIArg(scratch1);
     masm.passABIArg(obj);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementDontReportOOM));
-    masm.mov(ReturnReg, scratch);
+    masm.mov(ReturnReg, scratch1);
 
     masm.PopRegsInMask(save);
-    masm.branchIfFalseBool(scratch, failure->label());
+    masm.branchIfFalseBool(scratch1, failure->label());
 
     // Load the reallocated elements pointer.
-    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
+    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
 
     masm.bind(&capacityOk);
 
     // Increment initLength.
     masm.add32(Imm32(1), initLength);
 
     // If length is now <= index, increment length too.
     Label skipIncrementLength;
-    Address length(scratch, ObjectElements::offsetOfLength());
+    Address length(scratch1, ObjectElements::offsetOfLength());
     masm.branch32(Assembler::Above, length, index, &skipIncrementLength);
     masm.add32(Imm32(1), length);
     masm.bind(&skipIncrementLength);
 
     // Skip EmitPreBarrier as the memory is uninitialized.
+    Label doStore;
     masm.jump(&doStore);
 
     masm.bind(&inBounds);
 
     EmitPreBarrier(masm, element, MIRType::Value);
 
     masm.bind(&doStore);
-    EmitStoreDenseElement(masm, val, scratch, element);
+    EmitStoreDenseElement(masm, val, scratch1, element);
     if (needsPostBarrier())
-        emitPostBarrierElement(obj, val, scratch, index);
+        emitPostBarrierElement(obj, val, scratch1, index);
     return true;
 }
 
 bool
 IonCacheIRCompiler::emitArrayPush()
 {
     MOZ_ASSERT_UNREACHABLE("emitArrayPush not supported for IonCaches.");
     return false;
@@ -2027,29 +2036,26 @@ IonCacheIRCompiler::emitStoreTypedElemen
     Register index = allocator.useRegister(masm, reader.int32OperandId());
     ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
 
     TypedThingLayout layout = reader.typedThingLayout();
     Scalar::Type arrayType = reader.scalarType();
     bool handleOOB = reader.readBool();
 
     AutoScratchRegister scratch1(allocator, masm);
-
-    Maybe<AutoScratchRegister> scratch2;
-    if (arrayType != Scalar::Float32 && arrayType != Scalar::Float64)
-        scratch2.emplace(allocator, masm);
+    AutoScratchRegister scratch2(allocator, masm);
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     // Bounds check.
     Label done;
     LoadTypedThingLength(masm, layout, obj, scratch1);
-    masm.branch32(Assembler::BelowOrEqual, scratch1, index, handleOOB ? &done : failure->label());
+    masm.spectreBoundsCheck32(index, scratch1, scratch2, handleOOB ? &done : failure->label());
 
     // Load the elements vector.
     LoadTypedThingData(masm, layout, obj, scratch1);
 
     BaseIndex dest(scratch1, index, ScaleFromElemWidth(Scalar::byteSize(arrayType)));
 
     FloatRegister maybeTempDouble = ic_->asSetPropertyIC()->maybeTempDouble();
     FloatRegister maybeTempFloat32 = ic_->asSetPropertyIC()->maybeTempFloat32();
@@ -2061,17 +2067,17 @@ IonCacheIRCompiler::emitStoreTypedElemen
         if (!masm.convertConstantOrRegisterToFloat(cx_, val, tempFloat, failure->label()))
             return false;
         masm.storeToTypedFloatArray(arrayType, tempFloat, dest);
     } else if (arrayType == Scalar::Float64) {
         if (!masm.convertConstantOrRegisterToDouble(cx_, val, maybeTempDouble, failure->label()))
             return false;
         masm.storeToTypedFloatArray(arrayType, maybeTempDouble, dest);
     } else {
-        Register valueToStore = scratch2.ref();
+        Register valueToStore = scratch2;
         if (arrayType == Scalar::Uint8Clamped) {
             if (!masm.clampConstantOrRegisterToUint8(cx_, val, maybeTempDouble, valueToStore,
                                                      failure->label()))
             {
                 return false;
             }
         } else {
             if (!masm.truncateConstantOrRegisterToInt32(cx_, val, maybeTempDouble, valueToStore,
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3414,62 +3414,81 @@ LIRGenerator::visitStoreElement(MStoreEl
         if (ins->fallible())
             assignSnapshot(lir, Bailout_Hole);
         add(lir, ins);
         break;
       }
     }
 }
 
+static bool
+BoundsCheckNeedsSpectreTemp()
+{
+    // On x86, spectreBoundsCheck32 can emit better code if it has a scratch
+    // register and index masking is enabled.
+#ifdef JS_CODEGEN_X86
+    return JitOptions.spectreIndexMasking;
+#else
+    return false;
+#endif
+}
+
 void
 LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
 {
     MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
     MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
 
     const LUse object = useRegister(ins->object());
     const LUse elements = useRegister(ins->elements());
-    const LAllocation index = useRegisterOrConstant(ins->index());
+    const LAllocation index = useRegister(ins->index());
+
+    LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
 
     LInstruction* lir;
     switch (ins->value()->type()) {
       case MIRType::Value:
-        lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()));
+        lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()),
+                                              spectreTemp);
         break;
 
       default:
       {
         const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
-        lir = new(alloc()) LStoreElementHoleT(object, elements, index, value);
+        lir = new(alloc()) LStoreElementHoleT(object, elements, index, value, spectreTemp);
         break;
       }
     }
 
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins)
 {
     MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
     MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
 
     const LUse object = useRegister(ins->object());
     const LUse elements = useRegister(ins->elements());
-    const LAllocation index = useRegisterOrConstant(ins->index());
+    const LAllocation index = useRegister(ins->index());
+
+    LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
 
     LInstruction* lir;
     switch (ins->value()->type()) {
       case MIRType::Value:
-        lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()));
+        lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()),
+                                                  spectreTemp);
         break;
       default:
         const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
-        lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value);
+        lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value,
+                                                  spectreTemp);
         break;
     }
 
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 
@@ -3558,29 +3577,32 @@ LIRGenerator::visitArrayPopShift(MArrayP
 
 void
 LIRGenerator::visitArrayPush(MArrayPush* ins)
 {
     MOZ_ASSERT(ins->type() == MIRType::Int32);
 
     LUse object = useRegister(ins->object());
 
+    LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
+
     switch (ins->value()->type()) {
       case MIRType::Value:
       {
-        LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp());
+        LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp(),
+                                                    spectreTemp);
         define(lir, ins);
         assignSafepoint(lir, ins);
         break;
       }
 
       default:
       {
         const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
-        LArrayPushT* lir = new(alloc()) LArrayPushT(object, value, temp());
+        LArrayPushT* lir = new(alloc()) LArrayPushT(object, value, temp(), spectreTemp);
         define(lir, ins);
         assignSafepoint(lir, ins);
         break;
       }
     }
 }
 
 void
@@ -3726,28 +3748,16 @@ LIRGenerator::visitLoadTypedArrayElement
                                                                               temp());
     if (ins->fallible())
         assignSnapshot(lir, Bailout_Overflow);
     defineBox(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGenerator::visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic* ins)
-{
-    LLoadTypedArrayElementStatic* lir =
-        new(alloc()) LLoadTypedArrayElementStatic(useRegisterAtStart(ins->ptr()));
-
-    // In case of out of bounds, may bail out, or may jump to ool code.
-    if (ins->fallible())
-        assignSnapshot(lir, Bailout_BoundsCheck);
-    define(lir, ins);
-}
-
-void
 LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins)
 {
     MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
     MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
 
     if (ins->isSimdWrite()) {
         MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32x4, ins->value()->type() == MIRType::Float32x4);
         MOZ_ASSERT_IF(ins->writeType() == Scalar::Int8x16, ins->value()->type() == MIRType::Int8x16);
@@ -3796,26 +3806,29 @@ LIRGenerator::visitStoreTypedArrayElemen
     if (ins->isFloatWrite()) {
         MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32, ins->value()->type() == MIRType::Float32);
         MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64, ins->value()->type() == MIRType::Double);
     } else {
         MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
     }
 
     LUse elements = useRegister(ins->elements());
-    LAllocation length = useAnyOrConstant(ins->length());
-    LAllocation index = useRegisterOrConstant(ins->index());
+    LAllocation length = useAny(ins->length());
+    LAllocation index = useRegister(ins->index());
+    // For byte arrays, the value has to be in a byte register on x86.
     LAllocation value;
-
-    // For byte arrays, the value has to be in a byte register on x86.
     if (ins->isByteWrite())
         value = useByteOpRegisterOrNonDoubleConstant(ins->value());
     else
         value = useRegisterOrNonDoubleConstant(ins->value());
-    add(new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value), ins);
+
+    LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
+    auto* lir =
+        new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value, spectreTemp);
+    add(lir, ins);
 }
 
 void
 LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins)
 {
     MDefinition* obj = ins->object();
     MOZ_ASSERT(obj->type() == MIRType::Object);
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -5766,66 +5766,25 @@ InlinePropertyTable::appendRoots(MRootLi
 {
     for (const Entry* entry : entries_) {
         if (!entry->appendRoots(roots))
             return false;
     }
     return true;
 }
 
-SharedMem<void*>
-MLoadTypedArrayElementStatic::base() const
-{
-    return someTypedArray_->as<TypedArrayObject>().viewDataEither();
-}
-
-size_t
-MLoadTypedArrayElementStatic::length() const
-{
-    return someTypedArray_->as<TypedArrayObject>().byteLength();
-}
-
-bool
-MLoadTypedArrayElementStatic::congruentTo(const MDefinition* ins) const
-{
-    if (!ins->isLoadTypedArrayElementStatic())
-        return false;
-    const MLoadTypedArrayElementStatic* other = ins->toLoadTypedArrayElementStatic();
-    if (offset() != other->offset())
-        return false;
-    if (needsBoundsCheck() != other->needsBoundsCheck())
-        return false;
-    if (accessType() != other->accessType())
-        return false;
-    if (base() != other->base())
-        return false;
-    return congruentIfOperandsEqual(other);
-}
-
-SharedMem<void*>
-MStoreTypedArrayElementStatic::base() const
-{
-    return someTypedArray_->as<TypedArrayObject>().viewDataEither();
-}
-
 bool
 MGetPropertyCache::allowDoubleResult() const
 {
     if (!resultTypeSet())
         return true;
 
     return resultTypeSet()->hasType(TypeSet::DoubleType());
 }
 
-size_t
-MStoreTypedArrayElementStatic::length() const
-{
-    return someTypedArray_->as<TypedArrayObject>().byteLength();
-}
-
 MDefinition::AliasType
 MGetPropertyPolymorphic::mightAlias(const MDefinition* store) const
 {
     // Allow hoisting this instruction if the store does not write to a
     // slot read by this instruction.
 
     if (!store->isStoreFixedSlot() && !store->isStoreSlot())
         return AliasType::MayAlias;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1213,29 +1213,29 @@ class MInstruction
     // MIR instructions containing GC pointers should override this to append
     // these pointers to the root list.
     virtual bool appendRoots(MRootList& roots) const {
         return true;
     }
 
     // Instructions needing to hook into type analysis should return a
     // TypePolicy.
-    virtual TypePolicy* typePolicy() = 0;
+    virtual const TypePolicy* typePolicy() = 0;
     virtual MIRType typePolicySpecialization() = 0;
 };
 
 // Note: GenerateOpcodeFiles.py generates MOpcodes.h based on the
 // INSTRUCTION_HEADER* macros.
 #define INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                       \
     static const Opcode classOpcode = Opcode::opcode;                       \
     using MThisOpcode = M##opcode;
 
 #define INSTRUCTION_HEADER(opcode)                                          \
     INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                           \
-    virtual TypePolicy* typePolicy() override;                              \
+    virtual const TypePolicy* typePolicy() override;                        \
     virtual MIRType typePolicySpecialization() override;
 
 #define ALLOW_CLONE(typename)                                               \
     bool canClone() const override {                                        \
         return true;                                                        \
     }                                                                       \
     MInstruction* clone(TempAllocator& alloc,                               \
                         const MDefinitionVector& inputs) const override {   \
@@ -7933,17 +7933,17 @@ class MPhi final
         return &inputs_[index];
     }
     const MUse* getUseFor(size_t index) const override {
         return &inputs_[index];
     }
 
   public:
     INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(Phi)
-    virtual TypePolicy* typePolicy();
+    virtual const TypePolicy* typePolicy();
     virtual MIRType typePolicySpecialization();
 
     MPhi(TempAllocator& alloc, MIRType resultType)
       : MDefinition(classOpcode),
         inputs_(alloc),
         truncateKind_(NoTruncate),
         hasBackedgeType_(false),
         triedToSpecialize_(false),
@@ -10581,83 +10581,16 @@ class MLoadTypedArrayElementHole
     AliasSet getAliasSet() const override {
         return AliasSet::Load(AliasSet::UnboxedElement);
     }
     bool canProduceFloat32() const override { return arrayType_ == Scalar::Float32; }
 
     ALLOW_CLONE(MLoadTypedArrayElementHole)
 };
 
-// Load a value fallibly or infallibly from a statically known typed array.
-class MLoadTypedArrayElementStatic
-  : public MUnaryInstruction,
-    public ConvertToInt32Policy<0>::Data
-{
-    MLoadTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr,
-                                 int32_t offset = 0, bool needsBoundsCheck = true)
-      : MUnaryInstruction(classOpcode, ptr), someTypedArray_(someTypedArray), offset_(offset),
-        needsBoundsCheck_(needsBoundsCheck), fallible_(true)
-    {
-        int type = accessType();
-        if (type == Scalar::Float32)
-            setResultType(MIRType::Float32);
-        else if (type == Scalar::Float64)
-            setResultType(MIRType::Double);
-        else
-            setResultType(MIRType::Int32);
-    }
-
-    CompilerObject someTypedArray_;
-
-    // An offset to be encoded in the load instruction - taking advantage of the
-    // addressing modes. This is only non-zero when the access is proven to be
-    // within bounds.
-    int32_t offset_;
-    bool needsBoundsCheck_;
-    bool fallible_;
-
-  public:
-    INSTRUCTION_HEADER(LoadTypedArrayElementStatic)
-    TRIVIAL_NEW_WRAPPERS
-
-    Scalar::Type accessType() const {
-        return someTypedArray_->as<TypedArrayObject>().type();
-    }
-    SharedMem<void*> base() const;
-    size_t length() const;
-
-    MDefinition* ptr() const { return getOperand(0); }
-    int32_t offset() const { return offset_; }
-    void setOffset(int32_t offset) { offset_ = offset; }
-    bool congruentTo(const MDefinition* ins) const override;
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::UnboxedElement);
-    }
-
-    bool needsBoundsCheck() const { return needsBoundsCheck_; }
-    void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
-
-    bool fallible() const {
-        return fallible_;
-    }
-
-    void setInfallible() {
-        fallible_ = false;
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-    bool needTruncation(TruncateKind kind) override;
-    bool canProduceFloat32() const override { return accessType() == Scalar::Float32; }
-    void collectRangeInfoPreTrunc() override;
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(someTypedArray_);
-    }
-};
-
 // Base class for MIR ops that write unboxed scalar values.
 class StoreUnboxedScalarBase
 {
     Scalar::Type writeType_;
 
   protected:
     explicit StoreUnboxedScalarBase(Scalar::Type writeType)
       : writeType_(writeType)
@@ -10807,70 +10740,16 @@ class MStoreTypedArrayElementHole
 
     bool canConsumeFloat32(MUse* use) const override {
         return use == getUseFor(3) && arrayType() == Scalar::Float32;
     }
 
     ALLOW_CLONE(MStoreTypedArrayElementHole)
 };
 
-// Store a value infallibly to a statically known typed array.
-class MStoreTypedArrayElementStatic :
-    public MBinaryInstruction,
-    public StoreUnboxedScalarBase,
-    public StoreTypedArrayElementStaticPolicy::Data
-{
-    MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
-                                  int32_t offset = 0, bool needsBoundsCheck = true)
-        : MBinaryInstruction(classOpcode, ptr, v),
-          StoreUnboxedScalarBase(someTypedArray->as<TypedArrayObject>().type()),
-          someTypedArray_(someTypedArray),
-          offset_(offset), needsBoundsCheck_(needsBoundsCheck)
-    {}
-
-    CompilerObject someTypedArray_;
-
-    // An offset to be encoded in the store instruction - taking advantage of the
-    // addressing modes. This is only non-zero when the access is proven to be
-    // within bounds.
-    int32_t offset_;
-    bool needsBoundsCheck_;
-
-  public:
-    INSTRUCTION_HEADER(StoreTypedArrayElementStatic)
-    TRIVIAL_NEW_WRAPPERS
-
-    Scalar::Type accessType() const {
-        return writeType();
-    }
-
-    SharedMem<void*> base() const;
-    size_t length() const;
-
-    MDefinition* ptr() const { return getOperand(0); }
-    MDefinition* value() const { return getOperand(1); }
-    bool needsBoundsCheck() const { return needsBoundsCheck_; }
-    void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
-    int32_t offset() const { return offset_; }
-    void setOffset(int32_t offset) { offset_ = offset; }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-    TruncateKind operandTruncateKind(size_t index) const override;
-
-    bool canConsumeFloat32(MUse* use) const override {
-        return use == getUseFor(1) && accessType() == Scalar::Float32;
-    }
-    void collectRangeInfoPreTrunc() override;
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(someTypedArray_);
-    }
-};
-
 // Compute an "effective address", i.e., a compound computation of the form:
 //   base + index * scale + displacement
 class MEffectiveAddress
   : public MBinaryInstruction,
     public NoTypePolicy::Data
 {
     MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, int32_t displacement)
       : MBinaryInstruction(classOpcode, base, index),
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -327,62 +327,19 @@ MacroAssembler::moveValue(const Constant
 // Arithmetic functions
 
 void
 MacroAssembler::addPtr(ImmPtr imm, Register dest)
 {
     addPtr(ImmWord(uintptr_t(imm.value)), dest);
 }
 
-void
-MacroAssembler::inc32(RegisterOrInt32Constant* key)
-{
-    if (key->isRegister())
-        add32(Imm32(1), key->reg());
-    else
-        key->bumpConstant(1);
-}
-
-void
-MacroAssembler::dec32(RegisterOrInt32Constant* key)
-{
-    if (key->isRegister())
-        add32(Imm32(-1), key->reg());
-    else
-        key->bumpConstant(-1);
-}
-
 // ===============================================================
 // Branch functions
 
-void
-MacroAssembler::branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
-                         Label* label)
-{
-    branch32Impl(cond, length, key, label);
-}
-
-void
-MacroAssembler::branch32(Condition cond, const Address& length, const RegisterOrInt32Constant& key,
-                         Label* label)
-{
-    branch32Impl(cond, length, key, label);
-}
-
-template <typename T>
-void
-MacroAssembler::branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
-                             Label* label)
-{
-    if (key.isRegister())
-        branch32(cond, length, key.reg(), label);
-    else
-        branch32(cond, length, Imm32(key.constant()), label);
-}
-
 template <class L>
 void
 MacroAssembler::branchIfFalseBool(Register reg, L label)
 {
     // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
     branchTest32(Assembler::Zero, reg, Imm32(0xFF), label);
 }
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -815,21 +815,18 @@ class MacroAssembler : public MacroAssem
     //
     // On x86_shared, srcDest must be eax and edx will be clobbered.
     // On ARM, the chip must have hardware division instructions.
     inline void remainder32(Register rhs, Register srcDest, bool isUnsigned) PER_SHARED_ARCH;
 
     inline void divFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
     inline void divDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
 
-    inline void inc32(RegisterOrInt32Constant* key);
     inline void inc64(AbsoluteAddress dest) PER_ARCH;
 
-    inline void dec32(RegisterOrInt32Constant* key);
-
     inline void neg32(Register reg) PER_SHARED_ARCH;
     inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64);
 
     inline void negateFloat(FloatRegister reg) PER_SHARED_ARCH;
 
     inline void negateDouble(FloatRegister reg) PER_SHARED_ARCH;
 
     inline void absFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
@@ -933,23 +930,19 @@ class MacroAssembler : public MacroAssem
 
     // ===============================================================
     // Branch functions
 
     template <class L>
     inline void branch32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH;
     template <class L>
     inline void branch32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH;
-    inline void branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
-                         Label* label);
 
     inline void branch32(Condition cond, const Address& lhs, Register rhs, Label* label) PER_SHARED_ARCH;
     inline void branch32(Condition cond, const Address& lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH;
-    inline void branch32(Condition cond, const Address& length, const RegisterOrInt32Constant& key,
-                         Label* label);
 
     inline void branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
     inline void branch32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
 
     inline void branch32(Condition cond, const BaseIndex& lhs, Register rhs, Label* label)
         DEFINED_ON(x86_shared);
@@ -1273,21 +1266,16 @@ class MacroAssembler : public MacroAssem
     inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
 
     // Create an unconditional branch to the address given as argument.
     inline void branchToComputedAddress(const BaseIndex& address) PER_ARCH;
 
   private:
 
-    // Implementation for branch* methods.
-    template <typename T>
-    inline void branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
-                             Label* label);
-
     template <typename T, typename S, typename L>
     inline void branchPtrImpl(Condition cond, const T& lhs, const S& rhs, L label)
         DEFINED_ON(x86_shared);
 
     void branchPtrInNurseryChunkImpl(Condition cond, Register ptr, Label* label)
         DEFINED_ON(x86);
     template <typename T>
     void branchValueIsNurseryCellImpl(Condition cond, const T& value, Register temp, Label* label)
@@ -1357,22 +1345,30 @@ class MacroAssembler : public MacroAssem
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
 
     // Zeroes dest if the condition is true.
     inline void spectreZeroRegister(Condition cond, Register scratch, Register dest)
         DEFINED_ON(arm, arm64, mips_shared, x86_shared);
 
     // Performs a bounds check and zeroes the index register if out-of-bounds
     // (to mitigate Spectre).
-    inline void spectreBoundsCheck32(Register index, Register length, Register scratch,
+  private:
+
+    inline void spectreBoundsCheck32(Register index, const Operand& length, Register maybeScratch,
                                      Label* failure)
-        DEFINED_ON(arm, arm64, mips_shared, x86_shared);
-    inline void spectreBoundsCheck32(Register index, const Address& length, Register scratch,
+        DEFINED_ON(x86);
+
+  public:
+
+    inline void spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
                                      Label* failure)
-        DEFINED_ON(arm, arm64, mips_shared, x86_shared);
+        DEFINED_ON(arm, arm64, mips_shared, x86, x64);
+    inline void spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
+                                     Label* failure)
+        DEFINED_ON(arm, arm64, mips_shared, x86, x64);
 
     // ========================================================================
     // Canonicalization primitives.
     inline void canonicalizeDouble(FloatRegister reg);
     inline void canonicalizeDoubleIfDeterministic(FloatRegister reg);
 
     inline void canonicalizeFloat(FloatRegister reg);
     inline void canonicalizeFloatIfDeterministic(FloatRegister reg);
@@ -2116,24 +2112,16 @@ class MacroAssembler : public MacroAssem
             mov(JSReturnReg, dest.valueReg());
 #else
 #error "Bad architecture"
 #endif
     }
 
     inline void storeCallResultValue(TypedOrValueRegister dest);
 
-    using MacroAssemblerSpecific::store32;
-    void store32(const RegisterOrInt32Constant& key, const Address& dest) {
-        if (key.isRegister())
-            store32(key.reg(), dest);
-        else
-            store32(Imm32(key.constant()), dest);
-    }
-
     template <typename T>
     void guardedCallPreBarrier(const T& address, MIRType type) {
         Label done;
 
         branchTestNeedsIncrementalBarrier(Assembler::Zero, &done);
 
         if (type == MIRType::Value)
             branchTestGCThing(Assembler::NotEqual, address, &done);
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -1797,26 +1797,16 @@ void
 MLoadUnboxedScalar::computeRange(TempAllocator& alloc)
 {
     // We have an Int32 type and if this is a UInt32 load it may produce a value
     // outside of our range, but we have a bailout to handle those cases.
     setRange(GetTypedArrayRange(alloc, readType()));
 }
 
 void
-MLoadTypedArrayElementStatic::computeRange(TempAllocator& alloc)
-{
-    // We don't currently use MLoadTypedArrayElementStatic for uint32, so we
-    // don't have to worry about it returning a value outside our type.
-    MOZ_ASSERT(someTypedArray_->as<TypedArrayObject>().type() != Scalar::Uint32);
-
-    setRange(GetTypedArrayRange(alloc, someTypedArray_->as<TypedArrayObject>().type()));
-}
-
-void
 MArrayLength::computeRange(TempAllocator& alloc)
 {
     // Array lengths can go up to UINT32_MAX, but we only create MArrayLength
     // nodes when the value is known to be int32 (see the
     // OBJECT_FLAG_LENGTH_OVERFLOW flag).
     setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX));
 }
 
@@ -2668,28 +2658,16 @@ MToDouble::truncate()
     setResultType(MIRType::Int32);
     if (truncateKind() >= IndirectTruncate) {
         if (range())
             range()->wrapAroundToInt32();
     }
 }
 
 bool
-MLoadTypedArrayElementStatic::needTruncation(TruncateKind kind)
-{
-    // IndirectTruncate not possible, since it returns 'undefined'
-    // upon out of bounds read. Doing arithmetic on 'undefined' gives wrong
-    // results. So only set infallible if explicitly truncated.
-    if (kind == Truncate)
-        setInfallible();
-
-    return false;
-}
-
-bool
 MLimitedTruncate::needTruncation(TruncateKind kind)
 {
     setTruncateKind(kind);
     setResultType(MIRType::Int32);
     if (kind >= IndirectTruncate && range())
         range()->wrapAroundToInt32();
     return false;
 }
@@ -2800,23 +2778,16 @@ MStoreUnboxedScalar::operandTruncateKind
 MDefinition::TruncateKind
 MStoreTypedArrayElementHole::operandTruncateKind(size_t index) const
 {
     // An integer store truncates the stored value.
     return index == 3 && isIntegerWrite() ? Truncate : NoTruncate;
 }
 
 MDefinition::TruncateKind
-MStoreTypedArrayElementStatic::operandTruncateKind(size_t index) const
-{
-    // An integer store truncates the stored value.
-    return index == 1 && isIntegerWrite() ? Truncate : NoTruncate;
-}
-
-MDefinition::TruncateKind
 MDiv::operandTruncateKind(size_t index) const
 {
     return Min(truncateKind(), TruncateAfterBailouts);
 }
 
 MDefinition::TruncateKind
 MMod::operandTruncateKind(size_t index) const
 {
@@ -3264,46 +3235,16 @@ MLoadElementHole::collectRangeInfoPreTru
     Range indexRange(index());
     if (indexRange.isFiniteNonNegative()) {
         needsNegativeIntCheck_ = false;
         setNotGuard();
     }
 }
 
 void
-MLoadTypedArrayElementStatic::collectRangeInfoPreTrunc()
-{
-    Range range(ptr());
-
-    if (range.hasInt32LowerBound() && range.hasInt32UpperBound()) {
-        int64_t offset = this->offset();
-        int64_t lower = range.lower() + offset;
-        int64_t upper = range.upper() + offset;
-        int64_t length = this->length();
-        if (lower >= 0 && upper < length)
-            setNeedsBoundsCheck(false);
-    }
-}
-
-void
-MStoreTypedArrayElementStatic::collectRangeInfoPreTrunc()
-{
-    Range range(ptr());
-
-    if (range.hasInt32LowerBound() && range.hasInt32UpperBound()) {
-        int64_t offset = this->offset();
-        int64_t lower = range.lower() + offset;
-        int64_t upper = range.upper() + offset;
-        int64_t length = this->length();
-        if (lower >= 0 && upper < length)
-            setNeedsBoundsCheck(false);
-    }
-}
-
-void
 MClz::collectRangeInfoPreTrunc()
 {
     Range inputRange(input());
     if (!inputRange.canBeZero())
         operandIsNeverZero_ = true;
 }
 
 void
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -277,51 +277,16 @@ class ConstantOrRegister
         return dataValue();
     }
 
     const TypedOrValueRegister& reg() const {
         return dataReg();
     }
 };
 
-struct RegisterOrInt32Constant {
-    bool isRegister_;
-    union {
-        Register reg_;
-        int32_t constant_;
-    };
-
-    explicit RegisterOrInt32Constant(Register reg)
-      : isRegister_(true), reg_(reg)
-    { }
-
-    explicit RegisterOrInt32Constant(int32_t index)
-      : isRegister_(false), constant_(index)
-    { }
-
-    inline void bumpConstant(int diff) {
-        MOZ_ASSERT(!isRegister_);
-        constant_ += diff;
-    }
-    inline Register reg() const {
-        MOZ_ASSERT(isRegister_);
-        return reg_;
-    }
-    inline int32_t constant() const {
-        MOZ_ASSERT(!isRegister_);
-        return constant_;
-    }
-    inline bool isRegister() const {
-        return isRegister_;
-    }
-    inline bool isConstant() const {
-        return !isRegister_;
-    }
-};
-
 template <typename T>
 class TypedRegisterSet
 {
   public:
     typedef T RegType;
     typedef typename T::SetType SetType;
 
   private:
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -61,17 +61,17 @@ BoxInputsPolicy::staticAdjustInputs(Temp
         if (in->type() == MIRType::Value)
             continue;
         ins->replaceOperand(i, BoxAt(alloc, ins, in));
     }
     return true;
 }
 
 bool
-ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MIRType specialization = ins->typePolicySpecialization();
     if (specialization == MIRType::None)
         return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
 
     MOZ_ASSERT(ins->type() == MIRType::Double || ins->type() == MIRType::Int32 || ins->type() == MIRType::Float32);
 
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
@@ -116,17 +116,17 @@ AllDoublePolicy::staticAdjustInputs(Temp
         if (!replace->typePolicy()->adjustInputs(alloc, replace))
             return false;
     }
 
     return true;
 }
 
 bool
-ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
+ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
 {
     MOZ_ASSERT(def->isCompare());
     MCompare* compare = def->toCompare();
 
     // Convert Float32 operands to doubles
     for (size_t i = 0; i < 2; i++) {
         MDefinition* in = def->getOperand(i);
         if (in->type() == MIRType::Float32) {
@@ -264,17 +264,17 @@ ComparePolicy::adjustInputs(TempAllocato
         if (!replace->typePolicy()->adjustInputs(alloc, replace))
             return false;
     }
 
     return true;
 }
 
 bool
-SameValuePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
+SameValuePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
 {
     MOZ_ASSERT(def->isSameValue());
     MSameValue* sameValue = def->toSameValue();
     MIRType lhsType = sameValue->lhs()->type();
     MIRType rhsType = sameValue->rhs()->type();
 
     // If both operands are numbers, convert them to doubles.
     if (IsNumberType(lhsType) && IsNumberType(rhsType))
@@ -295,17 +295,17 @@ SameValuePolicy::adjustInputs(TempAlloca
         return true;
     }
 
     // Otherwise box both operands.
     return BoxInputsPolicy::staticAdjustInputs(alloc, def);
 }
 
 bool
-TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
+TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
 {
     MTypeBarrier* ins = def->toTypeBarrier();
     MIRType inputType = ins->getOperand(0)->type();
     MIRType outputType = ins->type();
 
     // Input and output type are already in accordance.
     if (inputType == outputType)
         return true;
@@ -350,17 +350,17 @@ TypeBarrierPolicy::adjustInputs(TempAllo
     // types.  The unexpected types would have changed Range Analysis
     // predictions.  As such, we need to prevent destructive optimizations.
     ins->block()->flagOperandsOfPrunedBranches(replace);
 
     return true;
 }
 
 bool
-TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MDefinition* op = ins->getOperand(0);
     switch (op->type()) {
       case MIRType::Value:
       case MIRType::Null:
       case MIRType::Undefined:
       case MIRType::Boolean:
       case MIRType::Int32:
@@ -381,17 +381,17 @@ TestPolicy::adjustInputs(TempAllocator& 
       default:
         ins->replaceOperand(0, BoxAt(alloc, ins, op));
         break;
     }
     return true;
 }
 
 bool
-BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MIRType specialization = ins->typePolicySpecialization();
     if (specialization == MIRType::None)
         return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
 
     MOZ_ASSERT(ins->type() == specialization);
     MOZ_ASSERT(specialization == MIRType::Int32 || specialization == MIRType::Double);
 
@@ -408,17 +408,17 @@ BitwisePolicy::adjustInputs(TempAllocato
         if (!replace->typePolicy()->adjustInputs(alloc, replace))
             return false;
     }
 
     return true;
 }
 
 bool
-PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MIRType specialization = ins->typePolicySpecialization();
     MOZ_ASSERT(specialization == MIRType::Int32 ||
                specialization == MIRType::Double ||
                specialization == MIRType::None);
 
     // Inputs will be boxed if either is non-numeric.
     if (specialization == MIRType::None)
@@ -581,51 +581,51 @@ Float32Policy<Op>::staticAdjustInputs(Te
 }
 
 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 
 template <unsigned Op>
 bool
-FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* def)
+FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* def) const
 {
     MIRType policyType = def->typePolicySpecialization();
     if (policyType == MIRType::Double)
         return DoublePolicy<Op>::staticAdjustInputs(alloc, def);
     return Float32Policy<Op>::staticAdjustInputs(alloc, def);
 }
 
-template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* def);
+template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
 
 template <unsigned Op>
 bool
 NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def)
 {
     EnsureOperandNotFloat32(alloc, def, Op);
     return true;
 }
 
 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 
 template <unsigned FirstOp>
 bool
-NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc, MInstruction* def)
+NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc, MInstruction* def) const
 {
     for (size_t op = FirstOp, e = def->numOperands(); op < e; op++)
         EnsureOperandNotFloat32(alloc, def, op);
     return true;
 }
 
-template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc, MInstruction* def);
-template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc, MInstruction* def);
-template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruction* def);
+template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
+template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
+template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruction* def) const;
 
 template <unsigned Op>
 bool
 SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
     MIRType laneType = SimdTypeToLaneType(ins->type());
 
@@ -851,36 +851,36 @@ SimdSameAsReturnedTypePolicy<Op>::static
 }
 
 template bool
 SimdSameAsReturnedTypePolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
 template bool
 SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
 
 bool
-SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     for (unsigned i = 0, e = ins->numOperands(); i < e; i++)
         MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization());
     return true;
 }
 
 template <unsigned Op>
 bool
-SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MOZ_ASSERT(ins->typePolicySpecialization() == ins->getOperand(Op)->type());
     return true;
 }
 
 template bool
-SimdPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* ins);
+SimdPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* ins) const;
 
 bool
-SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MSimdGeneralShuffle* s = ins->toSimdGeneralShuffle();
 
     for (unsigned i = 0; i < s->numVectors(); i++)
         MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization());
 
     // Next inputs are the lanes, which need to be int32
     for (unsigned i = 0; i < s->numLanes(); i++) {
@@ -894,30 +894,30 @@ SimdShufflePolicy::adjustInputs(TempAllo
         if (!replace->typePolicy()->adjustInputs(alloc, replace))
             return false;
     }
 
     return true;
 }
 
 bool
-SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     // First input is the mask, which has to be a boolean.
     MOZ_ASSERT(IsBooleanSimdType(ins->getOperand(0)->type()));
 
     // Next inputs are the two vectors of a particular type.
     for (unsigned i = 1; i < 3; i++)
         MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization());
 
     return true;
 }
 
 bool
-CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MCall* call = ins->toCall();
 
     MDefinition* func = call->getFunction();
     if (func->type() != MIRType::Object) {
         MInstruction* unbox = MUnbox::New(alloc, func, MIRType::Object, MUnbox::Fallible);
         call->block()->insertBefore(call, unbox);
         call->replaceFunction(unbox);
@@ -931,34 +931,34 @@ CallPolicy::adjustInputs(TempAllocator& 
             return false;
         EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i));
     }
 
     return true;
 }
 
 bool
-CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     // The first operand should be an object.
     if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins))
         return false;
 
     // Box the index and value operands.
     for (size_t i = 1, e = ins->numOperands(); i < e; i++) {
         MDefinition* in = ins->getOperand(i);
         if (in->type() == MIRType::Value)
             continue;
         ins->replaceOperand(i, BoxAt(alloc, ins, in));
     }
     return true;
 }
 
 bool
-InstanceOfPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def)
+InstanceOfPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) const
 {
     // Box first operand if it isn't object
     if (def->getOperand(0)->type() != MIRType::Object)
         if (!BoxPolicy<0>::staticAdjustInputs(alloc, def))
             return false;
 
     return true;
 }
@@ -1049,50 +1049,41 @@ StoreUnboxedScalarPolicy::adjustValueInp
 
     if (value != curValue)
         ins->replaceOperand(valueOperand, value);
 
     return true;
 }
 
 bool
-StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins))
         return false;
 
     MStoreUnboxedScalar* store = ins->toStoreUnboxedScalar();
     MOZ_ASSERT(IsValidElementsType(store->elements(), store->offsetAdjustment()));
     MOZ_ASSERT(store->index()->type() == MIRType::Int32);
 
     return adjustValueInput(alloc, store, store->writeType(), store->value(), 2);
 }
 
 bool
-StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MStoreTypedArrayElementHole* store = ins->toStoreTypedArrayElementHole();
     MOZ_ASSERT(store->elements()->type() == MIRType::Elements);
     MOZ_ASSERT(store->index()->type() == MIRType::Int32);
     MOZ_ASSERT(store->length()->type() == MIRType::Int32);
 
     return StoreUnboxedScalarPolicy::adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3);
 }
 
 bool
-StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
-{
-    MStoreTypedArrayElementStatic* store = ins->toStoreTypedArrayElementStatic();
-
-    return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) &&
-        StoreUnboxedScalarPolicy::adjustValueInput(alloc, ins, store->accessType(), store->value(), 1);
-}
-
-bool
-StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins))
         return false;
 
     if (!ObjectPolicy<3>::staticAdjustInputs(alloc, ins))
         return false;
 
     // Change the value input to a ToObjectOrNull instruction if it might be
@@ -1123,17 +1114,17 @@ StoreUnboxedObjectOrNullPolicy::adjustIn
 
     MInstruction* barrier = MPostWriteBarrier::New(alloc, store->typedObj(), replace);
     store->block()->insertBefore(store, barrier);
 
     return true;
 }
 
 bool
-StoreUnboxedStringPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+StoreUnboxedStringPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins))
         return false;
 
     // Change the value input to a ToString instruction if it might be
     // a non-null primitive.
     if (!ConvertToStringPolicy<2>::staticAdjustInputs(alloc, ins))
         return false;
@@ -1150,17 +1141,17 @@ StoreUnboxedStringPolicy::adjustInputs(T
     MDefinition* value = store->value();
     MOZ_ASSERT(value->type() == MIRType::String);
     MInstruction* barrier = MPostWriteBarrier::New(alloc, store->typedObj(), value);
     store->block()->insertBefore(store, barrier);
     return true;
 }
 
 bool
-ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MDefinition* in = ins->toClampToUint8()->input();
 
     switch (in->type()) {
       case MIRType::Int32:
       case MIRType::Double:
       case MIRType::Value:
         break;
@@ -1168,17 +1159,17 @@ ClampPolicy::adjustInputs(TempAllocator&
           ins->replaceOperand(0, BoxAt(alloc, ins, in));
         break;
     }
 
     return true;
 }
 
 bool
-FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
+FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const
 {
     MOZ_ASSERT(ins->numOperands() == 1);
     MIRType inputType = ins->getOperand(0)->type();
     MIRType outputType = ins->type();
 
     // Special case when output is a Float32, but input isn't.
     if (outputType == MIRType::Float32 && inputType != MIRType::Float32) {
         // Create a MToFloat32 to add between the MFilterTypeSet and
@@ -1261,17 +1252,16 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(ComparePolicy)                            \
     _(FilterTypeSetPolicy)                      \
     _(InstanceOfPolicy)                         \
     _(PowPolicy)                                \
     _(SameValuePolicy)                          \
     _(SimdAllPolicy)                            \
     _(SimdSelectPolicy)                         \
     _(SimdShufflePolicy)                        \
-    _(StoreTypedArrayElementStaticPolicy)       \
     _(StoreTypedArrayHolePolicy)                \
     _(StoreUnboxedScalarPolicy)                 \
     _(StoreUnboxedObjectOrNullPolicy)           \
     _(StoreUnboxedStringPolicy)                 \
     _(TestPolicy)                               \
     _(AllDoublePolicy)                          \
     _(ToDoublePolicy)                           \
     _(ToInt32Policy)                            \
@@ -1347,20 +1337,20 @@ namespace jit {
 
 // Define for all used TypePolicy specialization, the definition for
 // |TypePolicy::Data::thisTypePolicy|.  This function returns one constant
 // instance of the TypePolicy which is shared among all MIR Instructions of the
 // same type.
 //
 // This Macro use __VA_ARGS__ to account for commas of template parameters.
 #define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...)    \
-    TypePolicy *                                        \
+    const TypePolicy*                                   \
     __VA_ARGS__::Data::thisTypePolicy()                 \
     {                                                   \
-        static __VA_ARGS__ singletonType;               \
+        static constexpr __VA_ARGS__ singletonType;     \
         return &singletonType;                          \
     }
 
     TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
     TEMPLATE_TYPE_POLICY_LIST(template<> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
 
 } // namespace jit
@@ -1383,17 +1373,17 @@ thisTypeSpecialization()
 } // namespace
 
 // For each MIR Instruction, this macro define the |typePolicy| method which is
 // using the |thisTypePolicy| method.  The |thisTypePolicy| method is either a
 // member of the MIR Instruction, such as with MGetElementCache, a member
 // inherited from the TypePolicy::Data structure, or a member inherited from
 // NoTypePolicy if the MIR instruction has no type policy.
 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op)      \
-    TypePolicy *                                \
+    const TypePolicy*                           \
     js::jit::M##op::typePolicy()                \
     {                                           \
         return M##op::thisTypePolicy();         \
     }                                           \
                                                 \
     MIRType                                     \
     js::jit::M##op::typePolicySpecialization()  \
     {                                           \
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -27,17 +27,17 @@ class TypePolicy
 {
   public:
     // Analyze the inputs of the instruction and perform one of the following
     // actions for each input:
     //  * Nothing; the input already type-checks.
     //  * If untyped, optionally ask the input to try and specialize its value.
     //  * Replace the operand with a conversion instruction.
     //  * Insert an unconditional deoptimization (no conversion possible).
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) = 0;
+    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const = 0;
 };
 
 struct TypeSpecializationData
 {
   protected:
     // Specifies three levels of specialization:
     //  - < Value. This input is expected and required.
     //  - == None. This op should not be specialized.
@@ -51,377 +51,377 @@ struct TypeSpecializationData
     MIRType specialization() const {
         return specialization_;
     }
 };
 
 #define EMPTY_DATA_                                     \
     struct Data                                         \
     {                                                   \
-        static TypePolicy* thisTypePolicy();            \
+        static const TypePolicy* thisTypePolicy();      \
     }
 
 #define INHERIT_DATA_(DATA_TYPE)                        \
     struct Data : public DATA_TYPE                      \
     {                                                   \
-        static TypePolicy* thisTypePolicy();            \
+        static const TypePolicy* thisTypePolicy();      \
     }
 
 #define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
 
 class NoTypePolicy
 {
   public:
     struct Data
     {
-        static TypePolicy* thisTypePolicy() {
+        static const TypePolicy* thisTypePolicy() {
             return nullptr;
         }
     };
 };
 
 class BoxInputsPolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 class ArithPolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 class AllDoublePolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 class BitwisePolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 class ComparePolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 class SameValuePolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 // Policy for MTest instructions.
 class TestPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 class TypeBarrierPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 class CallPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 // Policy for MPow. First operand Double; second Double or Int32.
 class PowPolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 // Expect a string for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class StringPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a string for operand Op. Else a ToString instruction is inserted.
 template <unsigned Op>
 class ConvertToStringPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect an Boolean for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class BooleanPolicy final : private TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expects either an Int32 or a boxed Int32 for operand Op; may unbox if needed.
 template <unsigned Op>
 class UnboxedInt32Policy final : private TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect an Int for operand Op. Else a ToInt32 instruction is inserted.
 template <unsigned Op>
 class ConvertToInt32Policy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect an Int for operand Op. Else a TruncateToInt32 instruction is inserted.
 template <unsigned Op>
 class TruncateToInt32Policy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a double for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class DoublePolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a float32 for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class Float32Policy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a float32 OR a double for operand Op, but will prioritize Float32
 // if the result type is set as such. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class FloatingPointPolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 template <unsigned Op>
 class NoFloatPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Policy for guarding variadic instructions such as object / array state
 // instructions.
 template <unsigned FirstOp>
 class NoFloatPolicyAfter final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 // Box objects or strings as an input to a ToDouble instruction.
 class ToDoublePolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Box objects, strings and undefined as input to a ToInt32 instruction.
 class ToInt32Policy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Box objects as input to a ToString instruction.
 class ToStringPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 template <unsigned Op>
 class ObjectPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Single-object input. If the input is a Value, it is unboxed. If it is
 // a primitive, we use ValueToNonNullObject.
 typedef ObjectPolicy<0> SingleObjectPolicy;
 
 // Convert an operand to have a type identical to the scalar type of the
 // returned type of the instruction.
 template <unsigned Op>
 class SimdScalarPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 class SimdAllPolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 template <unsigned Op>
 class SimdPolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 class SimdSelectPolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 class SimdShufflePolicy final : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 // SIMD value-type policy, use the returned type of the instruction to determine
 // how to unbox its operand.
 template <unsigned Op>
 class SimdSameAsReturnedTypePolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 template <unsigned Op>
 class BoxPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Boxes everything except inputs of type Type.
 template <unsigned Op, MIRType Type>
 class BoxExceptPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
-    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Box if not a typical property id (string, symbol, int32).
 template <unsigned Op>
 class CacheIdPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
-    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Combine multiple policies.
 template <class... Policies>
 class MixPolicy final : public TypePolicy
 {
@@ -437,96 +437,87 @@ class MixPolicy final : public TypePolic
                MixPolicy::staticAdjustInputsHelper<Rest...>(alloc, ins);
     }
 
   public:
     EMPTY_DATA_;
     static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
         return MixPolicy::staticAdjustInputsHelper<Policies...>(alloc, ins);
     }
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 class CallSetElementPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 // First operand will be boxed to a Value (except for an object)
 // Second operand (if specified) will forcefully be unboxed to an object
 class InstanceOfPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 class StoreTypedArrayHolePolicy;
-class StoreTypedArrayElementStaticPolicy;
 
 class StoreUnboxedScalarPolicy : public TypePolicy
 {
   private:
     static MOZ_MUST_USE bool adjustValueInput(TempAllocator& alloc, MInstruction* ins,
                                               Scalar::Type arrayType, MDefinition* value,
                                               int valueOperand);
 
     friend class StoreTypedArrayHolePolicy;
-    friend class StoreTypedArrayElementStaticPolicy;
 
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 class StoreTypedArrayHolePolicy final : public StoreUnboxedScalarPolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
-};
-
-class StoreTypedArrayElementStaticPolicy final : public StoreUnboxedScalarPolicy
-{
-  public:
-    EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 class StoreUnboxedObjectOrNullPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 class StoreUnboxedStringPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) const override;
 };
 
 // Accepts integers and doubles. Everything else is boxed.
 class ClampPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 class FilterTypeSetPolicy final : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
+    MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override;
 };
 
 #undef SPECIALIZATION_DATA_
 #undef INHERIT_DATA_
 #undef EMPTY_DATA_
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -1762,28 +1762,16 @@ CodeGeneratorARM::generateInvalidateEpil
     masm.jump(thunk);
 
     // We should never reach this point in JIT code -- the invalidation thunk
     // should pop the invalidated JS frame and return directly to its caller.
     masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
 }
 
 void
-CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
 CodeGenerator::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
 {
     Register elements = ToRegister(lir->elements());
     AnyRegister output = ToAnyRegister(lir->output());
     Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
 
     Register oldval = ToRegister(lir->oldval());
     Register newval = ToRegister(lir->newval());
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -780,22 +780,16 @@ LIRGeneratorARM::lowerTruncateFToInt32(M
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Float32);
 
     define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
 }
 
 void
-LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
 LIRGenerator::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
 {
     MOZ_ASSERT(HasLDSTREXBHD());
     MOZ_ASSERT(ins->arrayType() <= Scalar::Uint32);
 
     MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
     MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
 
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -2189,47 +2189,41 @@ MacroAssembler::spectreMovePtr(Condition
 
 void
 MacroAssembler::spectreZeroRegister(Condition cond, Register, Register dest)
 {
     ma_mov(Imm32(0), dest, cond);
 }
 
 void
-MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
+MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
                                      Label* failure)
 {
     MOZ_ASSERT(index != length);
-    MOZ_ASSERT(length != scratch);
-    MOZ_ASSERT(index != scratch);
-
-    if (JitOptions.spectreIndexMasking)
-        move32(Imm32(0), scratch);
+    MOZ_ASSERT(length != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
 
     branch32(Assembler::BelowOrEqual, length, index, failure);
 
     if (JitOptions.spectreIndexMasking)
-        ma_mov(scratch, index, LeaveCC, Assembler::BelowOrEqual);
+        ma_mov(Imm32(0), index, Assembler::BelowOrEqual);
 }
 
 void
-MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
+MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
                                      Label* failure)
 {
     MOZ_ASSERT(index != length.base);
-    MOZ_ASSERT(length.base != scratch);
-    MOZ_ASSERT(index != scratch);
-
-    if (JitOptions.spectreIndexMasking)
-        move32(Imm32(0), scratch);
+    MOZ_ASSERT(length.base != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
 
     branch32(Assembler::BelowOrEqual, length, index, failure);
 
     if (JitOptions.spectreIndexMasking)
-        ma_mov(scratch, index, LeaveCC, Assembler::BelowOrEqual);
+        ma_mov(Imm32(0), index, Assembler::BelowOrEqual);
 }
 
 // ========================================================================
 // Memory access primitives.
 void
 MacroAssembler::storeUncanonicalizedDouble(FloatRegister src, const Address& addr)
 {
     ScratchRegisterScope scratch(*this);
--- a/js/src/jit/arm64/CodeGenerator-arm64.cpp
+++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp
@@ -564,28 +564,16 @@ getBase(U* mir)
 {
     switch (mir->base()) {
       case U::Heap: return HeapReg;
     }
     return InvalidReg;
 }
 
 void
-CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("CodeGenerator::visitLoadTypedArrayElementStatic");
-}
-
-void
-CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("CodeGenerator::visitStoreTypedArrayElementStatic");
-}
-
-void
 CodeGenerator::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
 {
     MOZ_CRASH("visitAsmJSLoadHeap");
 }
 
 void
 CodeGenerator::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
 {
--- a/js/src/jit/arm64/Lowering-arm64.cpp
+++ b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -276,22 +276,16 @@ LIRGeneratorARM64::lowerTruncateDToInt32
 
 void
 LIRGeneratorARM64::lowerTruncateFToInt32(MTruncateToInt32* ins)
 {
     MOZ_CRASH("lowerTruncateFToInt32");
 }
 
 void
-LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
 LIRGenerator::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
 LIRGenerator::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -1870,36 +1870,36 @@ MacroAssembler::spectreMovePtr(Condition
 void
 MacroAssembler::spectreZeroRegister(Condition cond, Register, Register dest)
 {
     Csel(ARMRegister(dest, 64), ARMRegister(dest, 64), vixl::xzr,
          Assembler::InvertCondition(cond));
 }
 
 void
-MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
+MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
                                      Label* failure)
 {
     MOZ_ASSERT(index != length);
-    MOZ_ASSERT(length != scratch);
-    MOZ_ASSERT(index != scratch);
+    MOZ_ASSERT(length != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
 
     branch32(Assembler::BelowOrEqual, length, index, failure);
 
     if (JitOptions.spectreIndexMasking)
         Csel(ARMRegister(index, 32), ARMRegister(index, 32), vixl::wzr, Assembler::Above);
 }
 
 void
-MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
+MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
                                      Label* failure)
 {
     MOZ_ASSERT(index != length.base);
-    MOZ_ASSERT(length.base != scratch);
-    MOZ_ASSERT(index != scratch);
+    MOZ_ASSERT(length.base != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
 
     branch32(Assembler::BelowOrEqual, length, index, failure);
 
     if (JitOptions.spectreIndexMasking)
         Csel(ARMRegister(index, 32), ARMRegister(index, 32), vixl::wzr, Assembler::Above);
 }
 
 // ========================================================================
--- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp
+++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp
@@ -1795,28 +1795,16 @@ CodeGeneratorMIPSShared::generateInvalid
 
     masm.jump(thunk);
 
     // We should never reach this point in JIT code -- the invalidation thunk
     // should pop the invalidated JS frame and return directly to its caller.
     masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
 }
 
-void
-CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
 class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPSShared>
 {
     MTableSwitch* mir_;
     CodeLabel jumpLabel_;
 
     void accept(CodeGeneratorMIPSShared* codegen) {
         codegen->visitOutOfLineTableSwitch(this);
     }
--- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -553,22 +553,16 @@ LIRGenerator::visitSubstr(MSubstr* ins)
                                          temp(),
                                          temp(),
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
 LIRGenerator::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
     MOZ_ASSERT(ins->arrayType() != Scalar::Float32);
     MOZ_ASSERT(ins->arrayType() != Scalar::Float64);
 
     MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
     MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
 
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
@@ -1012,25 +1012,25 @@ MacroAssembler::test32LoadPtr(Condition 
 void
 MacroAssembler::test32MovePtr(Condition cond, const Address& addr, Imm32 mask, Register src,
                               Register dest)
 {
     MOZ_CRASH();
 }
 
 void
-MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
+MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
                                      Label* failure)
 {
     MOZ_RELEASE_ASSERT(!JitOptions.spectreIndexMasking);
     branch32(Assembler::BelowOrEqual, length, index, failure);
 }
 
 void
-MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
+MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
                                      Label* failure)
 {
     MOZ_RELEASE_ASSERT(!JitOptions.spectreIndexMasking);
     branch32(Assembler::BelowOrEqual, length, index, failure);
 }
 
 void
 MacroAssembler::spectreMovePtr(Condition cond, Register src, Register dest)
--- a/js/src/jit/shared/CodeGenerator-shared-inl.h
+++ b/js/src/jit/shared/CodeGenerator-shared-inl.h
@@ -179,24 +179,16 @@ ToAnyRegister(const LAllocation* a)
 }
 
 static inline AnyRegister
 ToAnyRegister(const LDefinition* def)
 {
     return ToAnyRegister(def->output());
 }
 
-static inline RegisterOrInt32Constant
-ToRegisterOrInt32Constant(const LAllocation* a)
-{
-    if (a->isConstant())
-        return RegisterOrInt32Constant(ToInt32(a));
-    return RegisterOrInt32Constant(ToRegister(a));
-}
-
 static inline ValueOperand
 ToOutValue(LInstruction* ins)
 {
 #if defined(JS_NUNBOX32)
     return ValueOperand(ToRegister(ins->getDef(TYPE_INDEX)),
                         ToRegister(ins->getDef(PAYLOAD_INDEX)));
 #elif defined(JS_PUNBOX64)
     return ValueOperand(ToRegister(ins->getDef(0)));
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -6435,61 +6435,68 @@ class LStoreElementT : public LInstructi
         return getOperand(1);
     }
     const LAllocation* value() {
         return getOperand(2);
     }
 };
 
 // Like LStoreElementV, but supports indexes >= initialized length.
-class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
+class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
 {
   public:
     LIR_HEADER(StoreElementHoleV)
 
     LStoreElementHoleV(const LAllocation& object, const LAllocation& elements,
-                       const LAllocation& index, const LBoxAllocation& value)
+                       const LAllocation& index, const LBoxAllocation& value,
+                       const LDefinition& spectreTemp)
       : LInstructionHelper(classOpcode)
     {
         setOperand(0, object);
         setOperand(1, elements);
         setOperand(2, index);
         setBoxOperand(Value, value);
+        setTemp(0, spectreTemp);
     }
 
     static const size_t Value = 3;
 
     const MStoreElementHole* mir() const {
         return mir_->toStoreElementHole();
     }
     const LAllocation* object() {
         return getOperand(0);
     }
     const LAllocation* elements() {
         return getOperand(1);
     }
     const LAllocation* index() {
         return getOperand(2);
     }
+    const LDefinition* spectreTemp() {
+        return getTemp(0);
+    }
 };
 
 // Like LStoreElementT, but supports indexes >= initialized length.
-class LStoreElementHoleT : public LInstructionHelper<0, 4, 0>
+class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
 {
   public:
     LIR_HEADER(StoreElementHoleT)
 
     LStoreElementHoleT(const LAllocation& object, const LAllocation& elements,
-                       const LAllocation& index, const LAllocation& value)
+                       const LAllocation& index, const LAllocation& value,
+                       const LDefinition& spectreTemp)
       : LInstructionHelper(classOpcode)
     {
         setOperand(0, object);
         setOperand(1, elements);
         setOperand(2, index);
         setOperand(3, value);
+        setTemp(0, spectreTemp);
     }
 
     const MStoreElementHole* mir() const {
         return mir_->toStoreElementHole();
     }
     const LAllocation* object() {
         return getOperand(0);
     }
@@ -6497,64 +6504,74 @@ class LStoreElementHoleT : public LInstr
         return getOperand(1);
     }
     const LAllocation* index() {
         return getOperand(2);
     }
     const LAllocation* value() {
         return getOperand(3);
     }
+    const LDefinition* spectreTemp() {
+        return getTemp(0);
+    }
 };
 
 // Like LStoreElementV, but can just ignore assignment (for eg. frozen objects)
-class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
+class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
 {
   public:
     LIR_HEADER(FallibleStoreElementV)
 
     LFallibleStoreElementV(const LAllocation& object, const LAllocation& elements,
-                           const LAllocation& index, const LBoxAllocation& value)
+                           const LAllocation& index, const LBoxAllocation& value,
+                           const LDefinition& spectreTemp)
       : LInstructionHelper(classOpcode)
     {
         setOperand(0, object);
         setOperand(1, elements);
         setOperand(2, index);
         setBoxOperand(Value, value);
+        setTemp(0, spectreTemp);
     }
 
     static const size_t Value = 3;
 
     const MFallibleStoreElement* mir() const {
         return mir_->toFallibleStoreElement();
     }
     const LAllocation* object() {
         return getOperand(0);
     }
     const LAllocation* elements() {
         return getOperand(1);
     }
     const LAllocation* index() {
         return getOperand(2);
     }
+    const LDefinition* spectreTemp() {
+        return getTemp(0);
+    }
 };
 
 // Like LStoreElementT, but can just ignore assignment (for eg. frozen objects)
-class LFallibleStoreElementT : public LInstructionHelper<0, 4, 0>
+class LFallibleStoreElementT : public LInstructionHelper<0, 4, 1>
 {
   public:
     LIR_HEADER(FallibleStoreElementT)
 
     LFallibleStoreElementT(const LAllocation& object, const LAllocation& elements,
-                           const LAllocation& index, const LAllocation& value)
+                           const LAllocation& index, const LAllocation& value,
+                           const LDefinition& spectreTemp)
       : LInstructionHelper(classOpcode)
     {
         setOperand(0, object);
         setOperand(1, elements);
         setOperand(2, index);
         setOperand(3, value);
+        setTemp(0, spectreTemp);
     }
 
     const MFallibleStoreElement* mir() const {
         return mir_->toFallibleStoreElement();
     }
     const LAllocation* object() {
         return getOperand(0);
     }
@@ -6562,16 +6579,19 @@ class LFallibleStoreElementT : public LI
         return getOperand(1);
     }
     const LAllocation* index() {
         return getOperand(2);
     }
     const LAllocation* value() {
         return getOperand(3);
     }
+    const LDefinition* spectreTemp() {
+        return getTemp(0);
+    }
 };
 
 class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0>
 {
   public:
     LIR_HEADER(StoreUnboxedPointer)
 
     LStoreUnboxedPointer(LAllocation elements, LAllocation index, LAllocation value)
@@ -6676,67 +6696,77 @@ class LArrayPopShiftT : public LInstruct
     const LDefinition* temp0() {
         return getTemp(0);
     }
     const LDefinition* temp1() {
         return getTemp(1);
     }
 };
 
-class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
+class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 2>
 {
   public:
     LIR_HEADER(ArrayPushV)
 
-    LArrayPushV(const LAllocation& object, const LBoxAllocation& value, const LDefinition& temp)
+    LArrayPushV(const LAllocation& object, const LBoxAllocation& value, const LDefinition& temp,
+                const LDefinition& spectreTemp)
       : LInstructionHelper(classOpcode)
     {
         setOperand(0, object);
         setBoxOperand(Value, value);
         setTemp(0, temp);
+        setTemp(1, spectreTemp);
     }
 
     static const size_t Value = 1;
 
     const MArrayPush* mir() const {
         return mir_->toArrayPush();
     }
     const LAllocation* object() {
         return getOperand(0);
     }
     const LDefinition* temp() {
         return getTemp(0);
     }
-};
-
-class LArrayPushT : public LInstructionHelper<1, 2, 1>
+    const LDefinition* spectreTemp() {
+        return getTemp(1);
+    }
+};
+
+class LArrayPushT : public LInstructionHelper<1, 2, 2>
 {
   public:
     LIR_HEADER(ArrayPushT)
 
-    LArrayPushT(const LAllocation& object, const LAllocation& value, const LDefinition& temp)
+    LArrayPushT(const LAllocation& object, const LAllocation& value, const LDefinition& temp,
+                const LDefinition& spectreTemp)
       : LInstructionHelper(classOpcode)
     {
         setOperand(0, object);
         setOperand(1, value);
         setTemp(0, temp);
+        setTemp(1, spectreTemp);
     }
 
     const MArrayPush* mir() const {
         return mir_->toArrayPush();
     }
     const LAllocation* object() {
         return getOperand(0);
     }
     const LAllocation* value() {
         return getOperand(1);
     }
     const LDefinition* temp() {
         return getTemp(0);
     }
+    const LDefinition* spectreTemp() {
+        return getTemp(1);
+    }
 };
 
 class LArraySlice : public LCallInstructionHelper<1, 3, 2>
 {
   public:
     LIR_HEADER(ArraySlice)
 
     LArraySlice(const LAllocation& obj, const LAllocation& begin, const LAllocation& end,
@@ -6849,33 +6879,16 @@ class LLoadTypedArrayElementHole : publi
     const LAllocation* index() {
         return getOperand(1);
     }
     const LDefinition* temp() {
         return getTemp(0);
     }
 };
 
-class LLoadTypedArrayElementStatic : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(LoadTypedArrayElementStatic);
-    explicit LLoadTypedArrayElementStatic(const LAllocation& ptr)
-      : LInstructionHelper(classOpcode)
-    {
-        setOperand(0, ptr);
-    }
-    MLoadTypedArrayElementStatic* mir() const {
-        return mir_->toLoadTypedArrayElementStatic();
-    }
-    const LAllocation* ptr() {
-        return getOperand(0);
-    }
-};
-
 class LStoreUnboxedScalar : public LInstructionHelper<0, 3, 0>
 {
   public:
     LIR_HEADER(StoreUnboxedScalar)
 
     LStoreUnboxedScalar(const LAllocation& elements, const LAllocation& index,
                         const LAllocation& value)
       : LInstructionHelper(classOpcode)
@@ -6894,29 +6907,31 @@ class LStoreUnboxedScalar : public LInst
     const LAllocation* index() {
         return getOperand(1);
     }
     const LAllocation* value() {
         return getOperand(2);
     }
 };
 
-class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 0>
+class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 1>
 {
   public:
     LIR_HEADER(StoreTypedArrayElementHole)
 
     LStoreTypedArrayElementHole(const LAllocation& elements, const LAllocation& length,
-                                const LAllocation& index, const LAllocation& value)
+                                const LAllocation& index, const LAllocation& value,
+                                const LDefinition& spectreTemp)
       : LInstructionHelper(classOpcode)
     {
         setOperand(0, elements);
         setOperand(1, length);
         setOperand(2, index);
         setOperand(3, value);
+        setTemp(0, spectreTemp);
     }
 
     const MStoreTypedArrayElementHole* mir() const {
         return mir_->toStoreTypedArrayElementHole();
     }
     const LAllocation* elements() {
         return getOperand(0);
     }
@@ -6924,36 +6939,18 @@ class LStoreTypedArrayElementHole : publ
         return getOperand(1);
     }
     const LAllocation* index() {
         return getOperand(2);
     }
     const LAllocation* value() {
         return getOperand(3);
     }
-};
-
-class LStoreTypedArrayElementStatic : public LInstructionHelper<0, 2, 0>
-{
-  public:
-    LIR_HEADER(StoreTypedArrayElementStatic);
-    LStoreTypedArrayElementStatic(const LAllocation& ptr, const LAllocation& value)
-      : LInstructionHelper(classOpcode)
-    {
-        setOperand(0, ptr);
-        setOperand(1, value);
-    }
-    MStoreTypedArrayElementStatic* mir() const {
-        return mir_->toStoreTypedArrayElementStatic();
-    }
-    const LAllocation* ptr() {
-        return getOperand(0);
-    }
-    const LAllocation* value() {
-        return getOperand(1);
+    const LDefinition* spectreTemp() {
+        return getTemp(0);
     }
 };
 
 class LAtomicIsLockFree : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(AtomicIsLockFree)
 
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -285,19 +285,14 @@ class LIRGeneratorShared
         define(new(alloc()) LFloat32(f), mir);
     }
 
   public:
     // Whether to generate typed reads for element accesses with hole checks.
     static bool allowTypedElementHoleCheck() {
         return false;
     }
-
-    // Whether to generate typed array accesses on statically known objects.
-    static bool allowStaticTypedArrayAccesses() {
-        return false;
-    }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_Lowering_shared_h */
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -378,28 +378,16 @@ CodeGenerator::visitWasmUint32ToDouble(L
 
 void
 CodeGenerator::visitWasmUint32ToFloat32(LWasmUint32ToFloat32* lir)
 {
     masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
 }
 
 void
-CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
 CodeGeneratorX64::wasmStore(const wasm::MemoryAccessDesc& access, const LAllocation* value,
                             Operand dstAddr)
 {
     if (value->isConstant()) {
         MOZ_ASSERT(!access.isSimd());
 
         masm.memoryBarrierBefore(access.sync());
 
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -412,22 +412,16 @@ LIRGenerator::visitSubstr(MSubstr* ins)
                                          temp(),
                                          temp(),
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
 LIRGenerator::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(),
                                         temp(),
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -847,16 +847,60 @@ MacroAssembler::test32MovePtr(Condition 
 }
 
 void
 MacroAssembler::spectreMovePtr(Condition cond, Register src, Register dest)
 {
     cmovCCq(cond, Operand(src), dest);
 }
 
+void
+MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
+                                     Label* failure)
+{
+    MOZ_ASSERT(index != length);
+    MOZ_ASSERT(length != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
+
+    ScratchRegisterScope scratch(*this);
+    MOZ_ASSERT(index != scratch);
+    MOZ_ASSERT(length != scratch);
+
+    if (JitOptions.spectreIndexMasking)
+        move32(Imm32(0), scratch);
+
+    cmp32(index, length);
+    j(Assembler::AboveOrEqual, failure);
+
+    if (JitOptions.spectreIndexMasking)
+        cmovCCl(Assembler::AboveOrEqual, scratch, index);
+}
+
+void
+MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
+                                     Label* failure)
+{
+    MOZ_ASSERT(index != length.base);
+    MOZ_ASSERT(length.base != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
+
+    ScratchRegisterScope scratch(*this);
+    MOZ_ASSERT(index != scratch);
+    MOZ_ASSERT(length.base != scratch);
+
+    if (JitOptions.spectreIndexMasking)
+        move32(Imm32(0), scratch);
+
+    cmp32(index, Operand(length));
+    j(Assembler::AboveOrEqual, failure);
+
+    if (JitOptions.spectreIndexMasking)
+        cmovCCl(Assembler::AboveOrEqual, scratch, index);
+}
+
 // ========================================================================
 // Truncate floating point.
 
 void
 MacroAssembler::truncateFloat32ToUInt64(Address src, Address dest, Register temp,
                                         FloatRegister floatTemp)
 {
     Label done;
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
@@ -1113,52 +1113,16 @@ MacroAssembler::cmp32Move32(Condition co
 void
 MacroAssembler::spectreZeroRegister(Condition cond, Register scratch, Register dest)
 {
     // Note: use movl instead of move32/xorl to ensure flags are not clobbered.
     movl(Imm32(0), scratch);
     spectreMovePtr(cond, scratch, dest);
 }
 
-void
-MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register scratch,
-                                     Label* failure)
-{
-    MOZ_ASSERT(index != length);
-    MOZ_ASSERT(length != scratch);
-    MOZ_ASSERT(index != scratch);
-
-    if (JitOptions.spectreIndexMasking)
-        move32(Imm32(0), scratch);
-
-    cmp32(index, length);
-    j(Assembler::AboveOrEqual, failure);
-
-    if (JitOptions.spectreIndexMasking)
-        cmovCCl(Assembler::AboveOrEqual, scratch, index);
-}
-
-void
-MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register scratch,
-                                     Label* failure)
-{
-    MOZ_ASSERT(index != length.base);
-    MOZ_ASSERT(length.base != scratch);
-    MOZ_ASSERT(index != scratch);
-
-    if (JitOptions.spectreIndexMasking)
-        move32(Imm32(0), scratch);
-
-    cmp32(index, Operand(length));
-    j(Assembler::AboveOrEqual, failure);
-
-    if (JitOptions.spectreIndexMasking)
-        cmovCCl(Assembler::AboveOrEqual, scratch, index);
-}
-
 // ========================================================================
 // Canonicalization primitives.
 void
 MacroAssembler::canonicalizeFloat32x4(FloatRegister reg, FloatRegister scratch)
 {
     ScratchSimd128Scope scratch2(*this);
 
     MOZ_ASSERT(scratch.asSimd128() != scratch2.asSimd128());
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -254,65 +254,16 @@ CodeGenerator::visitWasmUint32ToFloat32(
 
     if (input != temp)
         masm.mov(input, temp);
 
     // Beware: convertUInt32ToFloat32 clobbers input.
     masm.convertUInt32ToFloat32(temp, output);
 }
 
-void
-CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
-{
-    const MLoadTypedArrayElementStatic* mir = ins->mir();
-    Scalar::Type accessType = mir->accessType();
-    MOZ_ASSERT_IF(accessType == Scalar::Float32, mir->type() == MIRType::Float32);
-
-    Register ptr = ToRegister(ins->ptr());
-    AnyRegister out = ToAnyRegister(ins->output());
-    OutOfLineLoadTypedArrayOutOfBounds* ool = nullptr;
-    uint32_t offset = mir->offset();
-
-    if (mir->needsBoundsCheck()) {
-        MOZ_ASSERT(offset == 0);
-        if (!mir->fallible()) {
-            ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(out, accessType);
-            addOutOfLineCode(ool, ins->mir());
-        }
-
-        masm.cmpPtr(ptr, ImmWord(mir->length()));
-        if (ool)
-            masm.j(Assembler::AboveOrEqual, ool->entry());
-        else
-            bailoutIf(Assembler::AboveOrEqual, ins->snapshot());
-    }
-
-    Operand srcAddr(ptr, int32_t(mir->base().asValue()) + int32_t(offset));
-    switch (accessType) {
-      case Scalar::Int8:         masm.movsblWithPatch(srcAddr, out.gpr()); break;
-      case Scalar::Uint8Clamped:
-      case Scalar::Uint8:        masm.movzblWithPatch(srcAddr, out.gpr()); break;
-      case Scalar::Int16:        masm.movswlWithPatch(srcAddr, out.gpr()); break;
-      case Scalar::Uint16:       masm.movzwlWithPatch(srcAddr, out.gpr()); break;
-      case Scalar::Int32:
-      case Scalar::Uint32:       masm.movlWithPatch(srcAddr, out.gpr()); break;
-      case Scalar::Float32:      masm.vmovssWithPatch(srcAddr, out.fpu()); break;
-      case Scalar::Float64:      masm.vmovsdWithPatch(srcAddr, out.fpu()); break;
-      default:                   MOZ_CRASH("Unexpected type");
-    }
-
-    if (accessType == Scalar::Float64)
-        masm.canonicalizeDouble(out.fpu());
-    if (accessType == Scalar::Float32)
-        masm.canonicalizeFloat(out.fpu());
-
-    if (ool)
-        masm.bind(ool->rejoin());
-}
-
 template <typename T>
 void
 CodeGeneratorX86::emitWasmLoad(T* ins)
 {
     const MWasmLoad* mir = ins->mir();
 
     uint32_t offset = mir->access().offset();
     MOZ_ASSERT(offset < wasm::OffsetGuardLimit);
@@ -416,65 +367,16 @@ CodeGenerator::visitAsmJSLoadHeap(LAsmJS
 
     masm.wasmLoad(mir->access(), srcAddr, out);
 
     if (ool)
         masm.bind(ool->rejoin());
 }
 
 void
-CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
-{
-    MStoreTypedArrayElementStatic* mir = ins->mir();
-    Scalar::Type accessType = mir->accessType();
-    Register ptr = ToRegister(ins->ptr());
-    const LAllocation* value = ins->value();
-
-    canonicalizeIfDeterministic(accessType, value);
-
-    uint32_t offset = mir->offset();
-    MOZ_ASSERT_IF(mir->needsBoundsCheck(), offset == 0);
-
-    Label rejoin;
-    if (mir->needsBoundsCheck()) {
-        MOZ_ASSERT(offset == 0);
-        masm.cmpPtr(ptr, ImmWord(mir->length()));
-        masm.j(Assembler::AboveOrEqual, &rejoin);
-    }
-
-    Operand dstAddr(ptr, int32_t(mir->base().asValue()) + int32_t(offset));
-    switch (accessType) {
-      case Scalar::Int8:
-      case Scalar::Uint8Clamped:
-      case Scalar::Uint8:
-        masm.movbWithPatch(ToRegister(value), dstAddr);
-        break;
-      case Scalar::Int16:
-      case Scalar::Uint16:
-        masm.movwWithPatch(ToRegister(value), dstAddr);
-        break;
-      case Scalar::Int32:
-      case Scalar::Uint32:
-        masm.movlWithPatch(ToRegister(value), dstAddr);
-        break;
-      case Scalar::Float32:
-        masm.vmovssWithPatch(ToFloatRegister(value), dstAddr);
-        break;
-      case Scalar::Float64:
-        masm.vmovsdWithPatch(ToFloatRegister(value), dstAddr);
-        break;
-      default:
-        MOZ_CRASH("unexpected type");
-    }
-
-    if (rejoin.used())
-        masm.bind(&rejoin);
-}
-
-void
 CodeGenerator::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
 {
     const MAsmJSStoreHeap* mir = ins->mir();
     MOZ_ASSERT(mir->offset() == 0);
 
     const LAllocation* ptr = ins->ptr();
     const LAllocation* value = ins->value();
     const LAllocation* boundsCheckLimit = ins->boundsCheckLimit();
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -465,40 +465,16 @@ LIRGenerator::visitAsmJSStoreHeap(MAsmJS
       case Scalar::Uint8Clamped:
       case Scalar::MaxTypedArrayViewType:
         MOZ_CRASH("unexpected array type");
     }
     add(lir, ins);
 }
 
 void
-LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
-{
-    // The code generated for StoreTypedArrayElementStatic is identical to that
-    // for AsmJSStoreHeap, and the same concerns apply.
-    LStoreTypedArrayElementStatic* lir;
-    switch (ins->accessType()) {
-      case Scalar::Int8: case Scalar::Uint8:
-      case Scalar::Uint8Clamped:
-        lir = new(alloc()) LStoreTypedArrayElementStatic(useRegister(ins->ptr()),
-                                                         useFixed(ins->value(), eax));
-        break;
-      case Scalar::Int16: case Scalar::Uint16:
-      case Scalar::Int32: case Scalar::Uint32:
-      case Scalar::Float32: case Scalar::Float64:
-        lir = new(alloc()) LStoreTypedArrayElementStatic(useRegisterAtStart(ins->ptr()),
-                                                         useRegisterAtStart(ins->value()));
-        break;
-      default: MOZ_CRASH("unexpected array type");
-    }
-
-    add(lir, ins);
-}
-
-void
 LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* memoryBase = ins->memoryBase();
     MOZ_ASSERT(memoryBase->type() == MIRType::Pointer);
 
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -55,19 +55,16 @@ class LIRGeneratorX86 : public LIRGenera
     void lowerUModI64(MMod* mod);
 
     void lowerPhi(MPhi* phi);
 
   public:
     static bool allowTypedElementHoleCheck() {
         return true;
     }
-    static bool allowStaticTypedArrayAccesses() {
-        return true;
-    }
 };
 
 typedef LIRGeneratorX86 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_Lowering_x86_h */
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -1036,16 +1036,74 @@ MacroAssembler::test32MovePtr(Condition 
 }
 
 void
 MacroAssembler::spectreMovePtr(Condition cond, Register src, Register dest)
 {
     cmovCCl(cond, Operand(src), dest);
 }
 
+void
+MacroAssembler::spectreBoundsCheck32(Register index, const Operand& length, Register maybeScratch,
+                                     Label* failure)
+{
+    Label failurePopValue;
+    bool pushedValue = false;
+    if (JitOptions.spectreIndexMasking) {
+        if (maybeScratch == InvalidReg) {
+            push(Imm32(0));
+            pushedValue = true;
+        } else {
+            move32(Imm32(0), maybeScratch);
+        }
+    }
+
+    cmp32(index, length);
+    j(Assembler::AboveOrEqual, pushedValue ? &failurePopValue : failure);
+
+    if (JitOptions.spectreIndexMasking) {
+        if (maybeScratch == InvalidReg) {
+            Label done;
+            cmovCCl(Assembler::AboveOrEqual, Operand(StackPointer, 0), index);
+            lea(Operand(StackPointer, sizeof(void*)), StackPointer);
+            jump(&done);
+
+            bind(&failurePopValue);
+            lea(Operand(StackPointer, sizeof(void*)), StackPointer);
+            jump(failure);
+
+            bind(&done);
+        } else {
+            cmovCCl(Assembler::AboveOrEqual, maybeScratch, index);
+        }
+    }
+}
+
+void
+MacroAssembler::spectreBoundsCheck32(Register index, Register length, Register maybeScratch,
+                                     Label* failure)
+{
+    MOZ_ASSERT(index != length);
+    MOZ_ASSERT(length != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
+
+    spectreBoundsCheck32(index, Operand(length), maybeScratch, failure);
+}
+
+void
+MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, Register maybeScratch,
+                                     Label* failure)
+{
+    MOZ_ASSERT(index != length.base);
+    MOZ_ASSERT(length.base != maybeScratch);
+    MOZ_ASSERT(index != maybeScratch);
+
+    spectreBoundsCheck32(index, Operand(length), maybeScratch, failure);
+}
+
 // ========================================================================
 // Truncate floating point.
 
 void
 MacroAssembler::truncateFloat32ToUInt64(Address src, Address dest, Register temp,
                                         FloatRegister floatTemp)
 {
     Label done;
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -44,25 +44,41 @@ if CONFIG['JS_BUNDLED_EDITLINE']:
     DIRS += ['editline']
 
 if not CONFIG['JS_DISABLE_SHELL']:
     DIRS += ['shell']
 
 TEST_DIRS += ['jsapi-tests', 'tests', 'gdb']
 
 if CONFIG['FUZZING_INTERFACES']:
-    if CONFIG['LIBFUZZER']:
-        # Add trace-pc coverage for libfuzzer
-        CFLAGS += ['-fsanitize-coverage=trace-pc-guard']
-        CXXFLAGS += ['-fsanitize-coverage=trace-pc-guard']
-
     TEST_DIRS += [
         'fuzz-tests',
     ]
 
+if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
+    # In addition to regular coverage provided by trace-pc-guard,
+    # LibFuzzer can use trace-cmp to instrument various compare instructions.
+    # Only use this feature on source files that do a lot of constant
+    # comparisons that would otherwise be hard to guess by LibFuzzer,
+    # as it comes with a larger overhead (requires -use_value_profile=1).
+    libfuzzer_flags = ['-fsanitize-coverage=trace-pc-guard']
+    libfuzzer_flags_cmp = ['-fsanitize-coverage=trace-pc-guard', '-fsanitize-coverage=trace-cmp']
+
+    # Any files that are targeted by LibFuzzer should be added here so they can
+    # be built with the necessary instrumentation flags, rather than just building
+    # the whole JS engine with instrumentation, to reduce the amount of noise.
+    SOURCES += [
+        'vm/StructuredClone.cpp',
+    ]
+    SOURCES['vm/StructuredClone.cpp'].flags += libfuzzer_flags_cmp
+else:
+    UNIFIED_SOURCES += [
+        'vm/StructuredClone.cpp',
+    ]
+
 CONFIGURE_SUBST_FILES += [
     'devtools/rootAnalysis/Makefile',
 ]
 CONFIGURE_DEFINE_FILES += [
     'js-confdefs.h',
 ]
 
 if not CONFIG['JS_STANDALONE']:
@@ -369,17 +385,16 @@ UNIFIED_SOURCES += [
     'vm/Scope.cpp',
     'vm/SelfHosting.cpp',
     'vm/Shape.cpp',
     'vm/SharedArrayObject.cpp',
     'vm/SharedImmutableStringsCache.cpp',
     'vm/Stack.cpp',
     'vm/Stopwatch.cpp',
     'vm/StringType.cpp',
-    'vm/StructuredClone.cpp',
     'vm/SymbolType.cpp',
     'vm/TaggedProto.cpp',
     'vm/Time.cpp',
     'vm/TypedArrayObject.cpp',
     'vm/TypeInference.cpp',
     'vm/UbiNode.cpp',
     'vm/UbiNodeCensus.cpp',
     'vm/UbiNodeShortestPaths.cpp',
@@ -692,19 +707,19 @@ if CONFIG['JS_BUILD_BINAST']:
     # These parts of BinAST should eventually move to release.
     SOURCES += [
         'frontend/BinSource.cpp',
         'frontend/BinToken.cpp'
     ]
 
     # Instrument BinAST files for fuzzing as we have a fuzzing target for BinAST.
     if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
-        SOURCES['frontend/BinSource.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
-        SOURCES['frontend/BinToken.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
-        SOURCES['frontend/BinTokenReaderTester.cpp'].flags += ['-fsanitize-coverage=trace-pc-guard']
+        SOURCES['frontend/BinSource.cpp'].flags += libfuzzer_flags_cmp
+        SOURCES['frontend/BinToken.cpp'].flags += libfuzzer_flags_cmp
+        SOURCES['frontend/BinTokenReaderTester.cpp'].flags += libfuzzer_flags_cmp
 
 # Wasm code should use WASM_HUGE_MEMORY instead of JS_CODEGEN_X64
 # so that it is easy to use the huge-mapping optimization for other
 # 64-bit platforms in the future.
 
 if CONFIG['JS_CODEGEN_X64'] or CONFIG['JS_CODEGEN_ARM64']:
     DEFINES['WASM_HUGE_MEMORY'] = True
 
--- a/js/src/vm/JSFunction-inl.h
+++ b/js/src/vm/JSFunction-inl.h
@@ -16,26 +16,16 @@ namespace js {
 inline const char*
 GetFunctionNameBytes(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
 {
     if (JSAtom* name = fun->explicitName())
         return bytes->encodeLatin1(cx, name);
     return js_anonymous_str;
 }
 
-static inline JSObject*
-SkipEnvironmentObjects(JSObject* env)
-{
-    if (!env)
-        return nullptr;
-    while (env->is<EnvironmentObject>())
-        env = &env->as<EnvironmentObject>().enclosingEnvironment();
-    return env;
-}
-
 inline bool
 CanReuseFunctionForClone(JSContext* cx, HandleFunction fun)
 {
     if (!fun->isSingleton())
         return false;
     if (fun->isInterpretedLazy()) {
         LazyScript* lazy = fun->lazyScript();
         if (lazy->hasBeenCloned())
@@ -63,17 +53,16 @@ CloneFunctionObjectIfNotSingleton(JSCont
      * with its type in existence.
      *
      * For functions inner to run once lambda, it may be possible that
      * the lambda runs multiple times and we repeatedly clone it. In these
      * cases, fall through to CloneFunctionObject, which will deep clone
      * the function's script.
      */
     if (CanReuseFunctionForClone(cx, fun)) {
-        RootedObject obj(cx, SkipEnvironmentObjects(parent));
         ObjectOpResult succeeded;
         if (proto && !SetPrototype(cx, fun, proto, succeeded))
             return nullptr;
         MOZ_ASSERT(!proto || succeeded);
         fun->setEnvironment(parent);
         return fun;
     }
 
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -2028,16 +2028,26 @@ js::NewScriptedFunction(JSContext* cx, u
     RootedObject enclosingEnv(cx, enclosingEnvArg);
     if (!enclosingEnv)
         enclosingEnv = &cx->global()->lexicalEnvironment();
     return NewFunctionWithProto(cx, nullptr, nargs, flags, enclosingEnv,
                                 atom, proto, allocKind, newKind);
 }
 
 #ifdef DEBUG
+static JSObject*
+SkipEnvironmentObjects(JSObject* env)
+{
+    if (!env)
+        return nullptr;
+    while (env->is<EnvironmentObject>())
+        env = &env->as<EnvironmentObject>().enclosingEnvironment();
+    return env;
+}
+
 static bool
 NewFunctionEnvironmentIsWellFormed(JSContext* cx, HandleObject env)
 {
     // Assert that the terminating environment is null, global, or a debug
     // scope proxy. All other cases of polluting global scope behavior are
     // handled by EnvironmentObjects (viz. non-syntactic DynamicWithObject and
     // NonSyntacticVariablesObject).
     RootedObject terminatingEnv(cx, SkipEnvironmentObjects(env));
@@ -2132,17 +2142,27 @@ NewFunctionClone(JSContext* cx, HandleFu
     }
 
     JSObject* cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
                                                  allocKind, newKind);
     if (!cloneobj)
         return nullptr;
     RootedFunction clone(cx, &cloneobj->as<JSFunction>());
 
-    uint16_t flags = fun->flags() & ~JSFunction::EXTENDED;
+    // JSFunction::HAS_INFERRED_NAME can be set at compile-time and at
+    // runtime. In the latter case we should actually clear the flag before
+    // cloning the function, but since we can't differentiate between both
+    // cases here, we'll end up with a momentarily incorrect function name.
+    // This will be fixed up in SetFunctionNameIfNoOwnName(), which should
+    // happen through JSOP_SETFUNNAME directly after JSOP_LAMBDA.
+    constexpr uint16_t NonCloneableFlags = JSFunction::EXTENDED |
+                                           JSFunction::RESOLVED_LENGTH |
+                                           JSFunction::RESOLVED_NAME;
+
+    uint16_t flags = fun->flags() & ~NonCloneableFlags;
     if (allocKind == AllocKind::FUNCTION_EXTENDED)
         flags |= JSFunction::EXTENDED;
 
     clone->setArgCount(fun->nargs());
     clone->setFlags(flags);
 
     JSAtom* atom = fun->displayAtom();
     if (atom)
@@ -2306,98 +2326,109 @@ SymbolToFunctionName(JSContext* cx, JS::
     if (desc) {
         // Step 4.c.
         if (!sb.append('[') || !sb.append(desc) || !sb.append(']'))
             return nullptr;
     }
     return sb.finishAtom();
 }
 
+static JSAtom*
+NameToFunctionName(JSContext* cx, HandleValue name, FunctionPrefixKind prefixKind)
+{
+    MOZ_ASSERT(name.isString() || name.isNumber());
+
+    if (prefixKind == FunctionPrefixKind::None)
+        return ToAtom<CanGC>(cx, name);
+
+    JSString* nameStr = ToString(cx, name);
+    if (!nameStr)
+        return nullptr;
+
+    StringBuffer sb(cx);
+    if (prefixKind == FunctionPrefixKind::Get) {
+        if (!sb.append("get "))
+            return nullptr;
+    } else {
+        if (!sb.append("set "))
+            return nullptr;
+    }
+    if (!sb.append(nameStr))
+        return nullptr;
+    return sb.finishAtom();
+}
+
 /*
  * Return an atom for use as the name of a builtin method with the given
  * property id.
  *
  * Function names are always strings. If id is the well-known @@iterator
  * symbol, this returns "[Symbol.iterator]".  If a prefix is supplied the final
  * name is |prefix + " " + name|.
  *
  * Implements steps 3-5 of 9.2.11 SetFunctionName in ES2016.
  */
 JSAtom*
 js::IdToFunctionName(JSContext* cx, HandleId id,
                      FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */)
 {
+    MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id) || JSID_IS_INT(id));
+
     // No prefix fastpath.
     if (JSID_IS_ATOM(id) && prefixKind == FunctionPrefixKind::None)
         return JSID_TO_ATOM(id);
 
     // Step 3 (implicit).
 
     // Step 4.
     if (JSID_IS_SYMBOL(id))
         return SymbolToFunctionName(cx, JSID_TO_SYMBOL(id), prefixKind);
 
+    // Step 5.
     RootedValue idv(cx, IdToValue(id));
-    RootedAtom name(cx, ToAtom<CanGC>(cx, idv));
-    if (!name)
-        return nullptr;
-
-    // Step 5.
-    return NameToFunctionName(cx, name, prefixKind);
-}
-
-JSAtom*
-js::NameToFunctionName(JSContext* cx, HandleAtom name,
-                       FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */)
-{
-    if (prefixKind == FunctionPrefixKind::None)
-        return name;
-
-    StringBuffer sb(cx);
-    if (prefixKind == FunctionPrefixKind::Get) {
-        if (!sb.append("get "))
-            return nullptr;
-    } else {
-        if (!sb.append("set "))
-            return nullptr;
-    }
-    if (!sb.append(name))
-        return nullptr;
-    return sb.finishAtom();
+    return NameToFunctionName(cx, idv, prefixKind);
 }
 
 bool
 js::SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name,
                                FunctionPrefixKind prefixKind)
 {
     MOZ_ASSERT(name.isString() || name.isSymbol() || name.isNumber());
 
+    // An inferred name may already be set if this function is a clone of a
+    // singleton function. Clear the inferred name in all cases, even if we
+    // end up not adding a new inferred name if |fun| is a class constructor.
+    if (fun->hasInferredName()) {
+        MOZ_ASSERT(fun->isSingleton());
+        fun->clearInferredName();
+    }
+
     if (fun->isClassConstructor()) {
         // A class may have static 'name' method or accessor.
         if (fun->contains(cx, cx->names().name))
             return true;
     } else {
         // Anonymous function shouldn't have own 'name' property at this point.
         MOZ_ASSERT(!fun->containsPure(cx->names().name));
     }
 
-    JSAtom* funNameAtom;
-    if (name.isSymbol()) {
-        funNameAtom = SymbolToFunctionName(cx, name.toSymbol(), prefixKind);
-    } else {
-        RootedAtom nameAtom(cx, ToAtom<CanGC>(cx, name));
-        if (!nameAtom)
-            return false;
-        funNameAtom = NameToFunctionName(cx, nameAtom, prefixKind);
-    }
-    if (!funNameAtom)
+    JSAtom* funName = name.isSymbol()
+                      ? SymbolToFunctionName(cx, name.toSymbol(), prefixKind)
+                      : NameToFunctionName(cx, name, prefixKind);
+    if (!funName)
         return false;
 
+    // RESOLVED_NAME shouldn't yet be set, at least as long as we don't
+    // support the "static public fields" or "decorators" proposal.
+    // These two proposals allow to access class constructors before
+    // JSOP_SETFUNNAME is executed, which means user code may have set the
+    // RESOLVED_NAME flag when we reach this point.
     MOZ_ASSERT(!fun->hasResolvedName());
-    fun->setInferredName(funNameAtom);
+
+    fun->setInferredName(funName);
 
     return true;
 }
 
 JSFunction*
 js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
                    unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */)
 {
--- a/js/src/vm/JSFunction.h
+++ b/js/src/vm/JSFunction.h
@@ -56,28 +56,30 @@ class JSFunction : public js::NativeObje
 
     enum Flags {
         INTERPRETED      = 0x0001,  /* function has a JSScript and environment. */
         CONSTRUCTOR      = 0x0002,  /* function that can be called as a constructor */
         EXTENDED         = 0x0004,  /* structure is FunctionExtended */
         BOUND_FUN        = 0x0008,  /* function was created with Function.prototype.bind. */
         WASM_OPTIMIZED   = 0x0010,  /* asm.js/wasm function that has a jit entry */
         HAS_GUESSED_ATOM = 0x0020,  /* function had no explicit name, but a
-                                       name was guessed for it anyway */
+                                       name was guessed for it anyway. See
+                                       atom_ for more info about this flag. */
         HAS_BOUND_FUNCTION_NAME_PREFIX = 0x0020, /* bound functions reuse the HAS_GUESSED_ATOM
                                                     flag to track if atom_ already contains the
                                                     "bound " function name prefix */
         LAMBDA           = 0x0040,  /* function comes from a FunctionExpression, ArrowFunction, or
                                        Function() call (not a FunctionDeclaration or nonstandard
                                        function-statement) */
         SELF_HOSTED      = 0x0080,  /* function is self-hosted builtin and must not be
                                        decompilable nor constructible. */
         HAS_INFERRED_NAME = 0x0100, /* function had no explicit name, but a name was
                                        set by SetFunctionName at compile time or
-                                       SetFunctionNameIfNoOwnName at runtime. */
+                                       SetFunctionNameIfNoOwnName at runtime. See
+                                       atom_ for more info about this flag. */
         INTERPRETED_LAZY = 0x0200,  /* function is interpreted but doesn't have a script yet */
         RESOLVED_LENGTH  = 0x0400,  /* f.length has been resolved (see fun_resolve). */
         RESOLVED_NAME    = 0x0800,  /* f.name has been resolved (see fun_resolve). */
 
         FUNCTION_KIND_SHIFT = 13,
         FUNCTION_KIND_MASK  = 0x7 << FUNCTION_KIND_SHIFT,
 
         ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
@@ -136,17 +138,52 @@ class JSFunction : public js::NativeObje
             JSObject* env_;            /* environment for new activations */
             union {
                 JSScript* script_;     /* interpreted bytecode descriptor or
                                           null; use the accessor! */
                 js::LazyScript* lazy_; /* lazily compiled script, or nullptr */
             } s;
         } scripted;
     } u;
-    js::GCPtrAtom atom_; /* name for diagnostics and decompiling */
+
+    // The |atom_| field can have different meanings depending on the function
+    // type and flags. It is used for diagnostics, decompiling, and
+    //
+    // 1. If the function is not a bound function:
+    //   a. If HAS_GUESSED_ATOM is not set, to store the initial value of the
+    //      "name" property of functions. But also see RESOLVED_NAME.
+    //   b. If HAS_GUESSED_ATOM is set, |atom_| is only used for diagnostics,
+    //      but must not be used for the "name" property.
+    //   c. If HAS_INFERRED_NAME is set, the function wasn't given an explicit
+    //      name in the source text, e.g. |function fn(){}|, but instead it
+    //      was inferred based on how the function was defined in the source
+    //      text. The exact name inference rules are defined in the ECMAScript
+    //      specification.
+    //      Name inference can happen at compile-time, for example in
+    //      |var fn = function(){}|, or it can happen at runtime, for example
+    //      in |var o = {[Symbol.iterator]: function(){}}|. When it happens at
+    //      compile-time, the HAS_INFERRED_NAME is set directly in the
+    //      bytecode emitter, when it happens at runtime, the flag is set when
+    //      evaluating the JSOP_SETFUNNAME bytecode.
+    //   d. HAS_GUESSED_ATOM and HAS_INFERRED_NAME cannot both be set.
+    //   e. |atom_| can be null if neither an explicit, nor inferred, nor a
+    //      guessed name was set.
+    //   f. HAS_INFERRED_NAME can be set for cloned singleton function, even
+    //      though the clone shouldn't receive an inferred name. See the
+    //      comments in NewFunctionClone() and SetFunctionNameIfNoOwnName()
+    //      for details.
+    //
+    // 2. If the function is a bound function:
+    //   a. To store the initial value of the "name" property.
+    //   b. If HAS_BOUND_FUNCTION_NAME_PREFIX is not set, |atom_| doesn't
+    //      contain the "bound " prefix which is prepended to the "name"
+    //      property of bound functions per ECMAScript.
+    //   c. Bound functions can never have an inferred or guessed name.
+    //   d. |atom_| is never null for bound functions.
+    js::GCPtrAtom atom_;
 
   public:
     /* Call objects must be created for each invocation of this function. */
     bool needsCallObject() const {
         MOZ_ASSERT(!isInterpretedLazy());
 
         if (isNative())
             return false;
@@ -799,20 +836,16 @@ NewScriptedFunction(JSContext* cx, unsig
                     HandleAtom atom, HandleObject proto = nullptr,
                     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                     NewObjectKind newKind = GenericObject,
                     HandleObject enclosingEnv = nullptr);
 extern JSAtom*
 IdToFunctionName(JSContext* cx, HandleId id,
                  FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
 
-extern JSAtom*
-NameToFunctionName(JSContext* cx, HandleAtom name,
-                   FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
-
 extern bool
 SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name,
                            FunctionPrefixKind prefixKind);
 
 extern JSFunction*
 DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
                unsigned nargs, unsigned flags,
                gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -2377,50 +2377,62 @@ js::SharedScriptData::new_(JSContext* cx
      * We expect bytecode is always non-empty. */
     MOZ_DIAGNOSTIC_ASSERT(codeLength > 0);
 
     entry->refCount_ = 0;
     entry->natoms_ = natoms;
     entry->codeLength_ = codeLength;
     entry->noteLength_ = srcnotesLength;
 
-
     /*
      * Call constructors to initialize the storage that will be accessed as a
      * GCPtrAtom array via atoms().
      */
     static_assert(offsetof(SharedScriptData, data_) % sizeof(GCPtrAtom) == 0,
                   "atoms must have GCPtrAtom alignment");
     GCPtrAtom* atoms = entry->atoms();
     for (unsigned i = 0; i < natoms; ++i)
         new (&atoms[i]) GCPtrAtom();
 
     // Sanity check the dataLength() computation
     MOZ_ASSERT(entry->dataLength() == dataLength);
 
     return entry;
 }
 
+inline
+js::ScriptBytecodeHasher::Lookup::Lookup(SharedScriptData* data)
+  : scriptData(data),
+    hash(mozilla::HashBytes(scriptData->data(), scriptData->dataLength()))
+{
+    scriptData->incRefCount();
+}
+
+inline
+js::ScriptBytecodeHasher::Lookup::~Lookup()
+{
+    scriptData->decRefCount();
+}
+
 bool
 JSScript::createScriptData(JSContext* cx, uint32_t codeLength, uint32_t srcnotesLength,
                            uint32_t natoms)
 {
     MOZ_ASSERT(!scriptData());
     SharedScriptData* ssd = SharedScriptData::new_(cx, codeLength, srcnotesLength, natoms);
     if (!ssd)
         return false;
 
     setScriptData(ssd);
     return true;
 }
 
 void
 JSScript::freeScriptData()
 {
-    MOZ_ASSERT(scriptData_->refCount() == 1);
     scriptData_->decRefCount();
     scriptData_ = nullptr;
 }
 
 void
 JSScript::setScriptData(js::SharedScriptData* data)
 {
     MOZ_ASSERT(!scriptData_);
@@ -2436,19 +2448,23 @@ JSScript::setScriptData(js::SharedScript
  */
 bool
 JSScript::shareScriptData(JSContext* cx)
 {
     SharedScriptData* ssd = scriptData();
     MOZ_ASSERT(ssd);
     MOZ_ASSERT(ssd->refCount() == 1);
 
+    // Calculate the hash before taking the lock. Because the data is reference
+    // counted, it also will be freed after releasing the lock if necessary.
+    ScriptBytecodeHasher::Lookup lookup(ssd);
+
     AutoLockScriptData lock(cx->runtime());
 
-    ScriptDataTable::AddPtr p = cx->scriptDataTable(lock).lookupForAdd(*ssd);
+    ScriptDataTable::AddPtr p = cx->scriptDataTable(lock).lookupForAdd(lookup);
     if (p) {
         MOZ_ASSERT(ssd != *p);
         freeScriptData();
         setScriptData(*p);
     } else {
         if (!cx->scriptDataTable(lock).add(p, ssd)) {
             freeScriptData();
             ReportOutOfMemory(cx);
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -851,29 +851,39 @@ class SharedScriptData
   private:
     SharedScriptData() = delete;
     SharedScriptData(const SharedScriptData&) = delete;
     SharedScriptData& operator=(const SharedScriptData&) = delete;
 };
 
 struct ScriptBytecodeHasher
 {
-    typedef SharedScriptData Lookup;
+    class Lookup {
+        friend struct ScriptBytecodeHasher;
+
+        SharedScriptData* scriptData;
+        HashNumber hash;
+
+      public:
+        explicit Lookup(SharedScriptData* data);
+        ~Lookup();
+    };
 
     static HashNumber hash(const Lookup& l) {
-        return mozilla::HashBytes(l.data(), l.dataLength());
+        return l.hash;
     }
     static bool match(SharedScriptData* entry, const Lookup& lookup) {
-        if (entry->natoms() != lookup.natoms())
-            return false;
-        if (entry->codeLength() != lookup.codeLength())
+        const SharedScriptData* data = lookup.scriptData;
+        if (entry->natoms() != data->natoms())
             return false;
-        if (entry->numNotes() != lookup.numNotes())
+        if (entry->codeLength() != data->codeLength())
             return false;
-        return mozilla::PodEqual<uint8_t>(entry->data(), lookup.data(), lookup.dataLength());
+        if (entry->numNotes() != data->numNotes())
+            return false;
+        return mozilla::PodEqual<uint8_t>(entry->data(), data->data(), data->dataLength());
     }
 };
 
 class AutoLockScriptData;
 
 using ScriptDataTable = HashSet<SharedScriptData*,
                                 ScriptBytecodeHasher,
                                 SystemAllocPolicy>;
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -4,27 +4,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/NativeObject-inl.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
+#include "mozilla/DebugOnly.h"
 
 #include "gc/Marking.h"
 #include "js/Value.h"
 #include "vm/Debugger.h"
 #include "vm/TypedArrayObject.h"
+#include "vm/UnboxedObject.h"
 
 #include "gc/Nursery-inl.h"
 #include "vm/ArrayObject-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/Shape-inl.h"
+#include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 using JS::AutoCheckCannotGC;
 using mozilla::ArrayLength;
 using mozilla::CheckedInt;
 using mozilla::DebugOnly;
 using mozilla::PodCopy;
@@ -1493,18 +1496,18 @@ AddOrChangeProperty(JSContext* cx, Handl
             MOZ_ASSERT(!desc.setter());
             return CallAddPropertyHookDense(cx, obj, index, desc.value());
         }
     }
 
     return CallAddPropertyHook(cx, obj, id, desc.value());
 }
 
-// Version of AddOrChangeProperty optimized for adding a plain data property.
-// This function doesn't handle integer ids as we may have to store them in
+// Versions of AddOrChangeProperty optimized for adding a plain data property.
+// These function doesn't handle integer ids as we may have to store them in
 // dense elements.
 static MOZ_ALWAYS_INLINE bool
 AddDataProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v)
 {
     MOZ_ASSERT(!JSID_IS_INT(id));
 
     if (!ReshapeForShadowedProp(cx, obj, id))
         return false;
@@ -1513,16 +1516,34 @@ AddDataProperty(JSContext* cx, HandleNat
     if (!shape)
         return false;
 
     UpdateShapeTypeAndValueForWritableDataProp(cx, obj, shape, id, v);
 
     return CallAddPropertyHook(cx, obj, id, v);
 }
 
+static MOZ_ALWAYS_INLINE bool
+AddDataPropertyNonDelegate(JSContext* cx, HandlePlainObject obj, HandleId id, HandleValue v)
+{
+    MOZ_ASSERT(!JSID_IS_INT(id));
+    MOZ_ASSERT(!obj->isDelegate());
+
+    // If we know this is a new property we can call addProperty instead of
+    // the slower putProperty.
+    Shape* shape = NativeObject::addEnumerableDataProperty(cx, obj, id);
+    if (!shape)
+        return false;
+
+    UpdateShapeTypeAndValueForWritableDataProp(cx, obj, shape, id, v);
+
+    MOZ_ASSERT(!obj->getClass()->getAddProperty());
+    return true;
+}
+
 static bool IsConfigurable(unsigned attrs) { return (attrs & JSPROP_PERMANENT) == 0; }
 static bool IsEnumerable(unsigned attrs) { return (attrs & JSPROP_ENUMERATE) != 0; }
 static bool IsWritable(unsigned attrs) { return (attrs & JSPROP_READONLY) == 0; }
 
 static bool IsAccessorDescriptor(unsigned attrs) {
     return (attrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0;
 }
 
@@ -2890,8 +2911,148 @@ js::NativeDeleteProperty(JSContext* cx, 
         obj->setDenseElementHole(cx, JSID_TO_INT(id));
     } else {
         if (!NativeObject::removeProperty(cx, obj, id))
             return false;
     }
 
     return SuppressDeletedProperty(cx, obj, id);
 }
+
+bool
+js::CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target, HandleNativeObject from,
+                             HandlePlainObject excludedItems, bool* optimized)
+{
+    MOZ_ASSERT(!target->isDelegate(),
+               "CopyDataPropertiesNative should only be called during object literal construction"
+               "which precludes that |target| is the prototype of any other object");
+
+    *optimized = false;
+
+    // Don't use the fast path if |from| may have extra indexed or lazy
+    // properties.
+    if (from->getDenseInitializedLength() > 0 ||
+        from->isIndexed() ||
+        from->is<TypedArrayObject>() ||
+        from->getClass()->getNewEnumerate() ||
+        from->getClass()->getEnumerate())
+    {
+        return true;
+    }
+
+    // Collect all enumerable data properties.
+    using ShapeVector = GCVector<Shape*, 8>;
+    Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
+
+    RootedShape fromShape(cx, from->lastProperty());
+    for (Shape::Range<NoGC> r(fromShape); !r.empty(); r.popFront()) {
+        Shape* shape = &r.front();
+        jsid id = shape->propid();
+        MOZ_ASSERT(!JSID_IS_INT(id));
+
+        if (!shape->enumerable())
+            continue;
+        if (excludedItems && excludedItems->contains(cx, id))
+            continue;
+
+        // Don't use the fast path if |from| contains non-data properties.
+        //
+        // This enables two optimizations:
+        // 1. We don't need to handle the case when accessors modify |from|.
+        // 2. String and symbol properties can be added in one go.
+        if (!shape->isDataProperty())
+            return true;
+
+        if (!shapes.append(shape))
+            return false;
+    }
+
+    *optimized = true;
+
+    // If |target| contains no own properties, we can directly call
+    // addProperty instead of the slower putProperty.
+    const bool targetHadNoOwnProperties = target->lastProperty()->isEmptyShape();
+
+    RootedId key(cx);
+    RootedValue value(cx);
+    for (size_t i = shapes.length(); i > 0; i--) {
+        Shape* shape = shapes[i - 1];
+        MOZ_ASSERT(shape->isDataProperty());
+        MOZ_ASSERT(shape->enumerable());
+
+        key = shape->propid();
+        MOZ_ASSERT(!JSID_IS_INT(key));
+
+        MOZ_ASSERT(from->isNative());
+        MOZ_ASSERT(from->lastProperty() == fromShape);
+
+        value = from->getSlot(shape->slot());
+        if (targetHadNoOwnProperties) {
+            MOZ_ASSERT(!target->contains(cx, key),
+                       "didn't expect to find an existing property");
+
+            if (!AddDataPropertyNonDelegate(cx, target, key, value))
+                return false;
+        } else {
+            if (!NativeDefineDataProperty(cx, target, key, value, JSPROP_ENUMERATE))
+                return false;
+        }
+    }
+
+    return true;
+}
+
+bool
+js::CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
+                             Handle<UnboxedPlainObject*> from, HandlePlainObject excludedItems,
+                             bool* optimized)
+{
+    MOZ_ASSERT(!target->isDelegate(),
+               "CopyDataPropertiesNative should only be called during object literal construction"
+               "which precludes that |target| is the prototype of any other object");
+
+    *optimized = false;
+
+    // Don't use the fast path for unboxed objects with expandos.
+    if (from->maybeExpando())
+        return true;
+
+    *optimized = true;
+
+    // If |target| contains no own properties, we can directly call
+    // addProperty instead of the slower putProperty.
+    const bool targetHadNoOwnProperties = target->lastProperty()->isEmptyShape();
+
+#ifdef DEBUG
+    RootedObjectGroup fromGroup(cx, from->group());
+#endif
+
+    RootedId key(cx);
+    RootedValue value(cx);
+    const UnboxedLayout& layout = from->layout();
+    for (size_t i = 0; i < layout.properties().length(); i++) {
+        const UnboxedLayout::Property& property = layout.properties()[i];
+        key = NameToId(property.name);
+        MOZ_ASSERT(!JSID_IS_INT(key));
+
+        if (excludedItems && excludedItems->contains(cx, key))
+            continue;
+
+        // Ensure the object stays unboxed.
+        MOZ_ASSERT(from->group() == fromGroup);
+
+        // All unboxed properties are enumerable.
+        value = from->getValue(property);
+
+        if (targetHadNoOwnProperties) {
+            MOZ_ASSERT(!target->contains(cx, key),
+                       "didn't expect to find an existing property");
+
+            if (!AddDataPropertyNonDelegate(cx, target, key, value))
+                return false;
+        } else {
+            if (!NativeDefineDataProperty(cx, target, key, value, JSPROP_ENUMERATE))
+                return false;
+        }
+    }
+
+    return true;
+}
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -24,16 +24,17 @@
 #include "vm/ShapedObject.h"
 #include "vm/StringType.h"
 #include "vm/TypeInference.h"
 
 namespace js {
 
 class Shape;
 class TenuringTracer;
+class UnboxedPlainObject;
 
 /*
  * To really poison a set of values, using 'magic' or 'undefined' isn't good
  * enough since often these will just be ignored by buggy code (see bug 629974)
  * in debug builds and crash in release builds. Instead, we use a safe-for-crash
  * pointer.
  */
 static MOZ_ALWAYS_INLINE void
@@ -1602,16 +1603,26 @@ MaybeNativeObject(JSObject* obj)
 }
 
 // Defined in NativeObject-inl.h.
 bool IsPackedArray(JSObject* obj);
 
 extern void
 AddPropertyTypesAfterProtoChange(JSContext* cx, NativeObject* obj, ObjectGroup* oldGroup);
 
+// Specializations of 7.3.23 CopyDataProperties(...) for NativeObjects.
+extern bool
+CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target, HandleNativeObject from,
+                         HandlePlainObject excludedItems, bool* optimized);
+
+extern bool
+CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
+                         Handle<UnboxedPlainObject*> from, HandlePlainObject excludedItems,
+                         bool* optimized);
+
 } // namespace js
 
 
 /*** Inline functions declared in JSObject.h that use the native declarations above **************/
 
 inline bool
 js::HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
 {
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -257,27 +257,16 @@ intrinsic_SubstringKernel(JSContext* cx,
     JSString* substr = SubstringKernel(cx, str, begin, length);
     if (!substr)
         return false;
 
     args.rval().setString(substr);
     return true;
 }
 
-static bool
-intrinsic_OwnPropertyKeys(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 1);
-    MOZ_ASSERT(args[0].isObject());
-    RootedObject obj(cx, &args[0].toObject());
-    return GetOwnPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
-                              args.rval());
-}
-
 static void
 ThrowErrorWithType(JSContext* cx, JSExnType type, const CallArgs& args)
 {
     uint32_t errorNumber = args[0].toInt32();
 
 #ifdef DEBUG
     const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber);
     MOZ_ASSERT(efs->argCount == args.length() - 1);
@@ -2154,16 +2143,69 @@ intrinsic_PromiseResolve(JSContext* cx, 
     JSObject* promise = js::PromiseResolve(cx, constructor, args[1]);
     if (!promise)
         return false;
 
     args.rval().setObject(*promise);
     return true;
 }
 
+static bool
+intrinsic_CopyDataPropertiesOrGetOwnKeys(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 3);
+    MOZ_ASSERT(args[0].isObject());
+    MOZ_ASSERT(args[1].isObject());
+    MOZ_ASSERT(args[2].isObjectOrNull());
+
+    RootedObject target(cx, &args[0].toObject());
+    RootedObject from(cx, &args[1].toObject());
+    RootedObject excludedItems(cx, args[2].toObjectOrNull());
+
+    if (from->isNative() &&
+        target->is<PlainObject>() &&
+        (!excludedItems || excludedItems->is<PlainObject>()))
+    {
+        bool optimized;
+        if (!CopyDataPropertiesNative(cx, target.as<PlainObject>(), from.as<NativeObject>(),
+                                      (excludedItems ? excludedItems.as<PlainObject>() : nullptr),
+                                      &optimized))
+        {
+            return false;
+        }
+
+        if (optimized) {
+            args.rval().setNull();
+            return true;
+        }
+    }
+
+    if (from->is<UnboxedPlainObject>() &&
+        target->is<PlainObject>() &&
+        (!excludedItems || excludedItems->is<PlainObject>()))
+    {
+        bool optimized;
+        if (!CopyDataPropertiesNative(cx, target.as<PlainObject>(), from.as<UnboxedPlainObject>(),
+                                      (excludedItems ? excludedItems.as<PlainObject>() : nullptr),
+                                      &optimized))
+        {
+            return false;
+        }
+
+        if (optimized) {
+            args.rval().setNull();
+            return true;
+        }
+    }
+
+    return GetOwnPropertyKeys(cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
+                              args.rval());
+}
+
 // The self-hosting global isn't initialized with the normal set of builtins.
 // Instead, individual C++-implemented functions that're required by
 // self-hosted code are defined as global functions. Accessing these
 // functions via a content compartment's builtins would be unsafe, because
 // content script might have changed the builtins' prototypes' members.
 // Installing the whole set of builtins in the self-hosting compartment, OTOH,
 // would be wasteful: it increases memory usage and initialization time for
 // self-hosting compartment.
@@ -2200,16 +2242,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_INLINABLE_FN("std_Object_create",         obj_create,                   2, 0, ObjectCreate),
     JS_FN("std_Object_propertyIsEnumerable",     obj_propertyIsEnumerable,     1,0),
     JS_FN("std_Object_getOwnPropertyNames",      obj_getOwnPropertyNames,      1,0),
     JS_FN("std_Object_toString",                 obj_toString,                 0,0),
 
     JS_INLINABLE_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf,      1,0,
                     ReflectGetPrototypeOf),
     JS_FN("std_Reflect_isExtensible",            Reflect_isExtensible,         1,0),
+    JS_FN("std_Reflect_ownKeys",                 Reflect_ownKeys,              1,0),
 
     JS_FN("std_Set_has",                         SetObject::has,               1,0),
     JS_FN("std_Set_iterator",                    SetObject::values,            0,0),
 
     JS_INLINABLE_FN("std_String_fromCharCode",   str_fromCharCode,             1,0, StringFromCharCode),
     JS_INLINABLE_FN("std_String_fromCodePoint",  str_fromCodePoint,            1,0, StringFromCodePoint),
     JS_INLINABLE_FN("std_String_charCodeAt",     str_charCodeAt,               1,0, StringCharCodeAt),
     JS_FN("std_String_includes",                 str_includes,                 1,0),
@@ -2267,28 +2310,28 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("ThrowRangeError",         intrinsic_ThrowRangeError,         4,0),
     JS_FN("ThrowTypeError",          intrinsic_ThrowTypeError,          4,0),
     JS_FN("ThrowSyntaxError",        intrinsic_ThrowSyntaxError,        4,0),
     JS_FN("ThrowInternalError",      intrinsic_ThrowInternalError,      4,0),
     JS_FN("GetErrorMessage",         intrinsic_GetErrorMessage,         1,0),
     JS_FN("CreateModuleSyntaxError", intrinsic_CreateModuleSyntaxError, 4,0),
     JS_FN("AssertionFailed",         intrinsic_AssertionFailed,         1,0),
     JS_FN("DumpMessage",             intrinsic_DumpMessage,             1,0),
-    JS_FN("OwnPropertyKeys",         intrinsic_OwnPropertyKeys,         1,0),
     JS_FN("MakeDefaultConstructor",  intrinsic_MakeDefaultConstructor,  2,0),
     JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
     JS_FN("_NameForTypedArray",      intrinsic_NameForTypedArray, 1,0),
     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
     JS_INLINABLE_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0,
                     IntrinsicFinishBoundFunctionInit),
     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
     JS_FN("IsRuntimeDefaultLocale",  intrinsic_IsRuntimeDefaultLocale,  1,0),
     JS_FN("AddContentTelemetry",     intrinsic_AddContentTelemetry,     2,0),
     JS_FN("_DefineDataProperty",     intrinsic_DefineDataProperty,      4,0),
     JS_FN("_DefineProperty",         intrinsic_DefineProperty,          6,0),
+    JS_FN("CopyDataPropertiesOrGetOwnKeys", intrinsic_CopyDataPropertiesOrGetOwnKeys, 3,0),
 
     JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing,        0,0,
                     IntrinsicIsConstructing),
     JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel,       3,0,
                     IntrinsicSubstringKernel),
     JS_INLINABLE_FN("ObjectHasPrototype",               intrinsic_ObjectHasPrototype,      2,0,
                     IntrinsicObjectHasPrototype),
     JS_INLINABLE_FN("UnsafeSetReservedSlot",            intrinsic_UnsafeSetReservedSlot,   3,0,
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1097,31 +1097,50 @@ JSStructuredCloneWriter::parseTransferab
 
         if (!JS_GetElement(cx, array, i, &v))
             return false;
 
         if (!v.isObject())
             return reportDataCloneError(JS_SCERR_TRANSFERABLE);
         tObj = &v.toObject();
 
+        RootedObject unwrappedObj(cx, CheckedUnwrap(tObj));
+        if (!unwrappedObj) {
+            ReportAccessDenied(cx);
+            return false;
+        }
+
         // Shared memory cannot be transferred because it is not possible (nor
         // desirable) to detach the memory in agents that already hold a
         // reference to it.
 
-        if (tObj->is<SharedArrayBufferObject>())
+        if (unwrappedObj->is<SharedArrayBufferObject>())
             return reportDataCloneError(JS_SCERR_SHMEM_TRANSFERABLE);
 
-        if (tObj->is<WasmMemoryObject>() && tObj->as<WasmMemoryObject>().isShared())
-            return reportDataCloneError(JS_SCERR_SHMEM_TRANSFERABLE);
+        else if (unwrappedObj->is<WasmMemoryObject>()) {
+            if (unwrappedObj->as<WasmMemoryObject>().isShared())
+                return reportDataCloneError(JS_SCERR_SHMEM_TRANSFERABLE);
+        }
 
         // External array buffers may be able to be transferred in the future,
         // but that is not currently implemented.
 
-        if (tObj->is<ArrayBufferObject>() && tObj->as<ArrayBufferObject>().isExternal())
-            return reportDataCloneError(JS_SCERR_TRANSFERABLE);
+        else if (unwrappedObj->is<ArrayBufferObject>()) {
+            if (unwrappedObj->as<ArrayBufferObject>().isExternal())
+                return reportDataCloneError(JS_SCERR_TRANSFERABLE);
+        }
+
+        else  {
+            if (!callbacks || !callbacks->canTransfer)
+                return reportDataCloneError(JS_SCERR_TRANSFERABLE);
+
+            JSAutoCompartment ac(cx, unwrappedObj);
+            if (!callbacks->canTransfer(cx, unwrappedObj, closure))
+                return false;
+        }
 
         // No duplicates allowed
         auto p = transferableObjects.lookupForAdd(tObj);
         if (p)
             return reportDataCloneError(JS_SCERR_DUP_TRANSFERABLE);
 
         if (!transferableObjects.add(p, tObj))
             return false;
@@ -1681,16 +1700,22 @@ JSStructuredCloneWriter::transferOwnersh
 
         if (cls == ESClass::ArrayBuffer) {
             tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
 
             // The current setup of the array buffer inheritance hierarchy doesn't
             // lend itself well to generic manipulation via proxies.
             Rooted<ArrayBufferObject*> arrayBuffer(cx, &CheckedUnwrap(obj)->as<ArrayBufferObject>());
             JSAutoCompartment ac(cx, arrayBuffer);
+
+            if (arrayBuffer->isDetached()) {
+                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+                return false;
+            }
+
             size_t nbytes = arrayBuffer->byteLength();
 
             if (arrayBuffer->isWasm() || arrayBuffer->isPreparedForAsmJS()) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_TRANSFER);
                 return false;
             }
 
             if (scope == JS::StructuredCloneScope::DifferentProcess) {
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -7987,38 +7987,41 @@ BaseCompiler::emitSetGlobal()
     if (!iter_.readSetGlobal(&id, &unused_value))
         return false;
 
     if (deadCode_)
         return true;
 
     const GlobalDesc& global = env_.globals[id];
 
-    ScratchI32 tmp(*this);
     switch (global.type()) {
       case ValType::I32: {
         RegI32 rv = popI32();
+        ScratchI32 tmp(*this);
         masm.store32(rv, addressOfGlobalVar(global, tmp));
         freeI32(rv);
         break;
       }
       case ValType::I64: {
         RegI64 rv = popI64();
+        ScratchI32 tmp(*this);
         masm.store64(rv, addressOfGlobalVar(global, tmp));
         freeI64(rv);
         break;
       }
       case ValType::F32: {
         RegF32 rv = popF32();
+        ScratchI32 tmp(*this);
         masm.storeFloat32(rv, addressOfGlobalVar(global, tmp));
         freeF32(rv);
         break;
       }
       case ValType::F64: {
         RegF64 rv = popF64();
+        ScratchI32 tmp(*this);
         masm.storeDouble(rv, addressOfGlobalVar(global, tmp));
         freeF64(rv);
         break;
       }
       default:
         MOZ_CRASH("Global variable type");
         break;
     }
--- a/layout/style/nsCSSAnonBoxList.h
+++ b/layout/style/nsCSSAnonBoxList.h
@@ -18,17 +18,18 @@
  * The first argument to
  * CSS_ANON_BOX/CSS_WRAPPER_ANON_BOX/CSS_NON_INHERITING_ANON_BOX is the C++
  * identifier of the atom.
  *
  * The second argument is the string value of the atom.
  *
  * CSS_NON_INHERITING_ANON_BOX is used for anon boxes that never inherit style
  * from anything.  This means all their property values are the initial values
- * of those properties.
+ * of those properties.  These ones must come first!  Code relies on this.
+ * If this macro is not defined, it will default to CSS_ANON_BOX.
  *
  * CSS_WRAPPER_ANON_BOX is used for anon boxes that are used as wrappers around
  * other frames during frametree fixup (e.g. table anonymous boxes, ruby
  * anonymous boxes, anonymous flex item blocks, etc).  These are also inheriting
  * anon boxes, just like CSS_ANON_BOX.  If this macro is not defined, it will
  * default to CSS_ANON_BOX.
  */
 
@@ -46,55 +47,67 @@
 #ifndef CSS_WRAPPER_ANON_BOX
 #  ifdef DEFINED_CSS_WRAPPER_ANON_BOX
 #    error "Recursive includes of nsCSSAnonBoxList.h?"
 #  endif /* DEFINED_CSS_WRAPPER_ANON_BOX */
 #  define CSS_WRAPPER_ANON_BOX(name_, value_) CSS_ANON_BOX(name_, value_)
 #  define DEFINED_CSS_WRAPPER_ANON_BOX
 #endif /* CSS_WRAPPER_ANON_BOX */
 
+//---------------------------------------------------------------------------
+// Non-inheriting ones, which must come first
+//---------------------------------------------------------------------------
+
+// Placeholder frames for out of flows.  Note that :-moz-placeholder is used for
+// the pseudo-element that represents the placeholder text in <input
+// placeholder="foo">, so we need a different string here.
+CSS_NON_INHERITING_ANON_BOX(oofPlaceholder, ":-moz-oof-placeholder")
+
+// Framesets
+CSS_NON_INHERITING_ANON_BOX(horizontalFramesetBorder, ":-moz-hframeset-border")
+CSS_NON_INHERITING_ANON_BOX(verticalFramesetBorder, ":-moz-vframeset-border")
+
+CSS_NON_INHERITING_ANON_BOX(framesetBlank, ":-moz-frameset-blank")
+
+CSS_NON_INHERITING_ANON_BOX(tableColGroup, ":-moz-table-column-group")
+CSS_NON_INHERITING_ANON_BOX(tableCol, ":-moz-table-column")
+
+CSS_NON_INHERITING_ANON_BOX(pageBreak, ":-moz-pagebreak")
+
+//---------------------------------------------------------------------------
+// Other ones
+//---------------------------------------------------------------------------
+
 // ::-moz-text, ::-moz-oof-placeholder, and ::-moz-first-letter-continuation are
 // non-elements which no rule will match.
 CSS_ANON_BOX(mozText, ":-moz-text")
-// placeholder frames for out of flows.  Note that :-moz-placeholder is used for
-// the pseudo-element that represents the placeholder text in <input
-// placeholder="foo">, so we need a different string here.
-CSS_NON_INHERITING_ANON_BOX(oofPlaceholder, ":-moz-oof-placeholder")
 // nsFirstLetterFrames for content outside the ::first-letter.
 CSS_ANON_BOX(firstLetterContinuation, ":-moz-first-letter-continuation")
 
 CSS_ANON_BOX(mozBlockInsideInlineWrapper, ":-moz-block-inside-inline-wrapper")
 CSS_WRAPPER_ANON_BOX(mozMathMLAnonymousBlock, ":-moz-mathml-anonymous-block")
 CSS_ANON_BOX(mozXULAnonymousBlock, ":-moz-xul-anonymous-block")
 
-// Framesets
-CSS_NON_INHERITING_ANON_BOX(horizontalFramesetBorder, ":-moz-hframeset-border")
-CSS_NON_INHERITING_ANON_BOX(verticalFramesetBorder, ":-moz-vframeset-border")
-
 CSS_ANON_BOX(mozLineFrame, ":-moz-line-frame")
 
 CSS_ANON_BOX(buttonContent, ":-moz-button-content")
 CSS_ANON_BOX(cellContent, ":-moz-cell-content")
 CSS_ANON_BOX(dropDownList, ":-moz-dropdown-list")
 CSS_ANON_BOX(fieldsetContent, ":-moz-fieldset-content")
-CSS_NON_INHERITING_ANON_BOX(framesetBlank, ":-moz-frameset-blank")
 CSS_ANON_BOX(mozDisplayComboboxControlFrame, ":-moz-display-comboboxcontrol-frame")
 CSS_ANON_BOX(htmlCanvasContent, ":-moz-html-canvas-content")
 
 CSS_WRAPPER_ANON_BOX(inlineTable, ":-moz-inline-table")
 CSS_WRAPPER_ANON_BOX(table, ":-moz-table")
 CSS_WRAPPER_ANON_BOX(tableCell, ":-moz-table-cell")
-CSS_NON_INHERITING_ANON_BOX(tableColGroup, ":-moz-table-column-group")
-CSS_NON_INHERITING_ANON_BOX(tableCol, ":-moz-table-column")
 CSS_ANON_BOX(tableWrapper, ":-moz-table-wrapper")
 CSS_WRAPPER_ANON_BOX(tableRowGroup, ":-moz-table-row-group")
 CSS_WRAPPER_ANON_BOX(tableRow, ":-moz-table-row")
 
 CSS_ANON_BOX(canvas, ":-moz-canvas")
-CSS_NON_INHERITING_ANON_BOX(pageBreak, ":-moz-pagebreak")
 CSS_ANON_BOX(page, ":-moz-page")
 CSS_ANON_BOX(pageContent, ":-moz-pagecontent")
 CSS_ANON_BOX(pageSequence, ":-moz-page-sequence")
 CSS_ANON_BOX(scrolledContent, ":-moz-scrolled-content")
 CSS_ANON_BOX(scrolledCanvas, ":-moz-scrolled-canvas")
 CSS_ANON_BOX(scrolledPageSequence, ":-moz-scrolled-page-sequence")
 CSS_ANON_BOX(columnContent, ":-moz-column-content")
 CSS_ANON_BOX(viewport, ":-moz-viewport")
--- a/layout/style/nsCSSAnonBoxes.cpp
+++ b/layout/style/nsCSSAnonBoxes.cpp
@@ -34,31 +34,22 @@ MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFL
 } // namespace mozilla
 
 #define CSS_ANON_BOX(name_, value_) \
   NS_STATIC_ATOM_SUBCLASS_DEFN_PTR(nsICSSAnonBoxPseudo, nsCSSAnonBoxes, name_)
 #include "nsCSSAnonBoxList.h"
 #undef CSS_ANON_BOX
 
 static const nsStaticAtomSetup sCSSAnonBoxAtomSetup[] = {
-  // Put the non-inheriting anon boxes first, so we can index into them easily.
-  #define CSS_ANON_BOX(name_, value_) /* nothing */
-  #define CSS_NON_INHERITING_ANON_BOX(name_, value_) \
+  // Non-inheriting boxes must come first in nsCSSAnonBoxList.h so that
+  // `NonInheriting` values can index into this array and other similar arrays.
+  #define CSS_ANON_BOX(name_, value_) \
     NS_STATIC_ATOM_SUBCLASS_SETUP( \
       mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
   #include "nsCSSAnonBoxList.h"
-  #undef CSS_NON_INHERITING_ANON_BOX
-  #undef CSS_ANON_BOX
-
-  #define CSS_ANON_BOX(name_, value_) \
-    NS_STATIC_ATOM_SUBCLASS_SETUP( \
-      mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
-  #define CSS_NON_INHERITING_ANON_BOX(name_, value_) /* nothing */
-  #include "nsCSSAnonBoxList.h"
-  #undef CSS_NON_INHERITING_ANON_BOX
   #undef CSS_ANON_BOX
 };
 
 void nsCSSAnonBoxes::RegisterStaticAtoms()
 {
   NS_RegisterStaticAtoms(sCSSAnonBoxAtomSetup);
 }
 
@@ -81,15 +72,8 @@ nsCSSAnonBoxes::IsTreePseudoElement(nsAt
 nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(nsAtom* aPseudo)
 {
   MOZ_ASSERT(IsNonInheritingAnonBox(aPseudo));
   Maybe<uint32_t> index =
     nsStaticAtomUtils::Lookup(aPseudo, sCSSAnonBoxAtomSetup);
   MOZ_RELEASE_ASSERT(index.isSome());
   return static_cast<NonInheriting>(*index);
 }
-
-/* static */ nsAtom*
-nsCSSAnonBoxes::GetNonInheritingPseudoAtom(NonInheriting aBoxType)
-{
-  MOZ_ASSERT(aBoxType < NonInheriting::_Count);
-  return *sCSSAnonBoxAtomSetup[static_cast<NonInheritingBase>(aBoxType)].mAtomp;
-}
--- a/layout/style/nsCSSAnonBoxes.h
+++ b/layout/style/nsCSSAnonBoxes.h
@@ -113,15 +113,11 @@ public:
 #undef CSS_WRAPPER_ANON_BOX
 #undef CSS_ANON_BOX
        false);
   }
 
   // Get the NonInheriting type for a given pseudo tag.  The pseudo tag must
   // test true for IsNonInheritingAnonBox.
   static NonInheriting NonInheritingTypeForPseudoTag(nsAtom* aPseudo);
-
-  // Get the atom for a given non-inheriting anon box type.  aBoxType must be <
-  // NonInheriting::_Count.
-  static nsAtom* GetNonInheritingPseudoAtom(NonInheriting aBoxType);
 };
 
 #endif /* nsCSSAnonBoxes_h___ */
--- a/mobile/android/installer/allowed-dupes.mn
+++ b/mobile/android/installer/allowed-dupes.mn
@@ -43,10 +43,9 @@ modules/devtools/shared/apps/Simulator.j
 res/table-remove-column-active.gif
 res/table-remove-column-hover.gif
 res/table-remove-column.gif
 res/table-remove-row-active.gif
 res/table-remove-row-hover.gif
 res/table-remove-row.gif
 res/multilocale.txt
 modules/commonjs/index.js
-chrome/toolkit/content/global/XPCNativeWrapper.js
 update.locale
--- a/security/sandbox/chromium/base/win/scoped_handle.cc
+++ b/security/sandbox/chromium/base/win/scoped_handle.cc
@@ -108,17 +108,19 @@ ActiveVerifier* ActiveVerifier::Get() {
   if (!g_active_verifier)
     ActiveVerifier::InstallVerifier();
 
   return g_active_verifier;
 }
 
 bool CloseHandleWrapper(HANDLE handle) {
   if (!::CloseHandle(handle))
-    CHECK(false);  // CloseHandle failed.
+    // Making this DCHECK as we are hitting this frequently, looks like we are
+    // closing handles twice somewhere. See bug 1449480.
+    DCHECK(false);  // CloseHandle failed.
   return true;
 }
 
 // Assigns the g_active_verifier global within the GetLock() lock.
 // If |existing_verifier| is non-null then |enabled| is ignored.
 void ThreadSafeAssignOrCreateActiveVerifier(ActiveVerifier* existing_verifier,
                                             bool enabled) {
   AutoNativeLock lock(*GetLock());
--- a/testing/web-platform/meta/preload/link-header-preload-delay-onload.html.ini
+++ b/testing/web-platform/meta/preload/link-header-preload-delay-onload.html.ini
@@ -1,3 +1,4 @@
 [link-header-preload-delay-onload.html]
   disabled:
     if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1437081
+    if os == "mac": https://bugzilla.mozilla.org/show_bug.cgi?id=1437081
--- a/testing/web-platform/tests/webmessaging/message-channels/close.html
+++ b/testing/web-platform/tests/webmessaging/message-channels/close.html
@@ -33,28 +33,16 @@ async_test(t => {
         e.ports[0].postMessage('TESTMSG');
         setTimeout(t.step_func_done(), time_to_wait_for_messages);
       });
     c2.port2.postMessage('TEST', [c.port2]);
   }, 'Message sent to closed port from transferred port should not arrive.');
 
 async_test(t => {
     const c = new MessageChannel();
-    c.port1.onmessage = t.unreached_func('Should not have delivered message');
-    c.port2.close();
-    const c2 = new MessageChannel();
-    c2.port1.onmessage = t.step_func(e => {
-        e.ports[0].postMessage('TESTMSG');
-        setTimeout(t.step_func_done(), time_to_wait_for_messages);
-      });
-    c2.port2.postMessage('TEST', [c.port2]);
-  }, 'Message sent from transferred closed port should not arrive.');
-
-async_test(t => {
-    const c = new MessageChannel();
     let isClosed = false;
     c.port1.onmessage = t.step_func_done(e => {
         assert_true(isClosed);
         assert_equals(e.data, 'TEST');
       });
     c.port2.postMessage('TEST');
     c.port2.close();
     isClosed = true;
deleted file mode 100644
--- a/toolkit/content/XPCNativeWrapper.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * Moved to C++ implementation in XPConnect.  See bug 281988.
- */
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -1,12 +1,11 @@
 toolkit.jar:
 %  content global %content/global/ contentaccessible=yes
 *  content/global/license.html
-   content/global/XPCNativeWrapper.js
    content/global/minimal-xul.css
 *  content/global/xul.css
    content/global/components.css
    content/global/textbox.css
    content/global/menulist.css
    content/global/autocomplete.css
    content/global/aboutAbout.js
    content/global/aboutAbout.xhtml
--- a/toolkit/content/tests/reftests/bug-442419-progressmeter-max-ref.xul
+++ b/toolkit/content/tests/reftests/bug-442419-progressmeter-max-ref.xul
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <progressmeter value="50"/> <!-- default is max = 100 -->
+  <progressmeter value="100"/> <!-- default is max = 100 -->
 </window>
 
--- a/toolkit/content/tests/reftests/bug-442419-progressmeter-max.xul
+++ b/toolkit/content/tests/reftests/bug-442419-progressmeter-max.xul
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <progressmeter  max="198" value="99"/> <!-- 50% -->
+  <progressmeter  max="198" value="198"/> <!-- 100% -->
 </window>
 
--- a/toolkit/content/tests/reftests/reftest.list
+++ b/toolkit/content/tests/reftests/reftest.list
@@ -1,6 +1,6 @@
-fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!isDebugBuild) random-if(cocoaWidget||/^Windows\x20NT\x206\.2/.test(http.oscpu)||(/^Windows\x20NT\x2010\.0/.test(http.oscpu))) == bug-442419-progressmeter-max.xul bug-442419-progressmeter-max-ref.xul # fails most of the time on Mac because progress meter animates; Bug 1439988
+== bug-442419-progressmeter-max.xul bug-442419-progressmeter-max-ref.xul
 != textbox-multiline-default-value.xul textbox-multiline-empty.xul
 == videocontrols-dynamically-add-cc.html videocontrols-dynamically-add-cc-ref.html
 == audio-with-bogus-url.html audio-with-bogus-url-ref.html
 == audio-dynamically-change-small-width.html audio-dynamically-change-small-width-ref.html
 == audio-with-padding.html audio-with-padding-ref.html
--- a/xpcom/ds/nsBaseHashtable.h
+++ b/xpcom/ds/nsBaseHashtable.h
@@ -260,65 +260,75 @@ public:
    */
   MOZ_MUST_USE LookupResult Lookup(KeyType aKey)
   {
     return LookupResult(this->GetEntry(aKey), *this);
   }
 
   struct EntryPtr {
   private:
-    EntryType& mEntry;
+    EntryType* mEntry;
     bool mExistingEntry;
+    nsBaseHashtable& mTable;
     // For debugging purposes
 #ifdef DEBUG
-    nsBaseHashtable& mTable;
     uint32_t mTableGeneration;
     bool mDidInitNewEntry;
 #endif
 
   public:
     EntryPtr(nsBaseHashtable& aTable, EntryType* aEntry, bool aExistingEntry)
-      : mEntry(*aEntry)
+      : mEntry(aEntry)
       , mExistingEntry(aExistingEntry)
+      , mTable(aTable)
 #ifdef DEBUG
-      , mTable(aTable)
       , mTableGeneration(aTable.GetGeneration())
       , mDidInitNewEntry(false)
 #endif
     {}
     ~EntryPtr()
     {
-      MOZ_ASSERT(mExistingEntry || mDidInitNewEntry,
-                 "Forgot to call OrInsert() on a new entry");
+      MOZ_ASSERT(mExistingEntry || mDidInitNewEntry || !mEntry,
+                 "Forgot to call OrInsert() or OrRemove() on a new entry");
     }
 
     // Is there something stored in the table already?
     explicit operator bool() const
     {
       MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
       return mExistingEntry;
     }
 
     template <class F>
     UserDataType OrInsert(F func)
     {
       MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
+      MOZ_ASSERT(mEntry);
       if (!mExistingEntry) {
-        mEntry.mData = func();
+        mEntry->mData = func();
 #ifdef DEBUG
         mDidInitNewEntry = true;
 #endif
       }
-      return mEntry.mData;
+      return mEntry->mData;
+    }
+
+    void OrRemove()
+    {
+      MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
+      MOZ_ASSERT(mEntry);
+      mTable.RemoveEntry(mEntry);
+      mEntry = nullptr;
     }
 
     MOZ_MUST_USE DataType& Data()
     {
       MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
-      return mEntry.mData;
+      MOZ_ASSERT(mEntry);
+      return mEntry->mData;
     }
   };
 
   /**
    * Looks up aKey in the hashtable and returns an object that allows you to
    * insert a new entry into the hashtable for that key if an existing entry
    * isn't found for it.
    *
--- a/xpcom/tests/gtest/TestHashtables.cpp
+++ b/xpcom/tests/gtest/TestHashtables.cpp
@@ -469,16 +469,38 @@ TEST(Hashtables, DataHashtable_LookupFor
 
   // Lookup().Remove() should remove all entries.
   for (auto& entity : gEntities) {
     if (auto entry = UniToEntity.Lookup(entity.mUnicode)) {
       entry.Remove();
     }
   }
   ASSERT_TRUE(0 == UniToEntity.Count());
+
+  // Remove newly added entries via OrRemove.
+  for (auto& entity : gEntities) {
+    auto entry = UniToEntity.LookupForAdd(entity.mUnicode);
+    ASSERT_FALSE(entry);
+    entry.OrRemove();
+  }
+  ASSERT_TRUE(0 == UniToEntity.Count());
+
+  // Remove existing entries via OrRemove.
+  for (auto& entity : gEntities) {
+    auto entry = UniToEntity.LookupForAdd(entity.mUnicode);
+    const char* val = entry.OrInsert([&entity] () { return entity.mStr; });
+    ASSERT_FALSE(entry);
+    ASSERT_TRUE(val == entity.mStr);
+    ASSERT_TRUE(entry.Data() == entity.mStr);
+
+    auto entry2 = UniToEntity.LookupForAdd(entity.mUnicode);
+    ASSERT_TRUE(entry2);
+    entry2.OrRemove();
+  }
+  ASSERT_TRUE(0 == UniToEntity.Count());
 }
 
 TEST(Hashtables, ClassHashtable_LookupForAdd)
 {
   // check a class-hashtable LookupForAdd with null values
   nsClassHashtable<nsCStringHashKey,TestUniChar> EntToUniClass(ENTITY_COUNT);
 
   for (auto& entity : gEntities) {
@@ -514,9 +536,31 @@ TEST(Hashtables, ClassHashtable_LookupFo
 
   // Lookup().Remove() should remove all entries.
   for (auto& entity : gEntities) {
     if (auto entry = EntToUniClass.Lookup(nsDependentCString(entity.mStr))) {
       entry.Remove();
     }
   }
   ASSERT_TRUE(0 == EntToUniClass.Count());
+
+  // Remove newly added entries via OrRemove.
+  for (auto& entity : gEntities) {
+    auto entry = EntToUniClass.LookupForAdd(nsDependentCString(entity.mStr));
+    ASSERT_FALSE(entry);
+    entry.OrRemove();
+  }
+  ASSERT_TRUE(0 == EntToUniClass.Count());
+
+  // Remove existing entries via OrRemove.
+  for (auto& entity : gEntities) {
+    auto entry = EntToUniClass.LookupForAdd(nsDependentCString(entity.mStr));
+    const TestUniChar* val = entry.OrInsert([] () { return nullptr; });
+    ASSERT_FALSE(entry);
+    ASSERT_TRUE(val == nullptr);
+    ASSERT_TRUE(entry.Data() == nullptr);
+
+    auto entry2 = EntToUniClass.LookupForAdd(nsDependentCString(entity.mStr));
+    ASSERT_TRUE(entry2);
+    entry2.OrRemove();
+  }
+  ASSERT_TRUE(0 == EntToUniClass.Count());
 }