Merge mozilla-central to autoland. a=merge CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Sun, 18 Mar 2018 00:25:33 +0200
changeset 462253 c3aa7eaf94e807196c5b7f2a1ccd7b0cbe6dd8f9
parent 462252 023918b79066a9b3edc1bd52dd0ec477fbf98555 (current diff)
parent 462247 efce78e62b6dac195e7cb4898684da54155d1661 (diff)
child 462254 6b3f3316dd39e00c27121322d30011b456f3f2aa
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
devtools/client/inspector/fonts/test/browser_fontinspector_copy-URL.js
devtools/client/jar.mn
devtools/client/themes/images/copy.svg
dom/base/test/test_xbl_userdata.xhtml
js/xpconnect/crashtests/462926.html
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -275,16 +275,18 @@ GetInstantiatorExecutable(const DWORD aP
   if (NS_FAILED(rv)) {
     return false;
   }
 
   file.forget(aOutClientExe);
   return NS_SUCCEEDED(rv);
 }
 
+#if defined(MOZ_TELEMETRY_REPORTING) || defined(MOZ_CRASHREPORTER)
+
 /**
  * Appends version information in the format "|a.b.c.d".
  * If there is no version information, we append nothing.
  */
 static void
 AppendVersionInfo(nsIFile* aClientExe, nsAString& aStrToAppend)
 {
   MOZ_ASSERT(!NS_IsMainThread());
@@ -328,75 +330,92 @@ AppendVersionInfo(nsIFile* aClientExe, n
   aStrToAppend.AppendInt(minor);
   aStrToAppend.Append(dot);
   aStrToAppend.AppendInt(patch);
   aStrToAppend.Append(dot);
   aStrToAppend.AppendInt(build);
 }
 
 static void
-AccumulateInstantiatorTelemetry(nsIFile* aClientExe, const nsAString& aValue)
+AccumulateInstantiatorTelemetry(const nsAString& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!aValue.IsEmpty()) {
 #if defined(MOZ_TELEMETRY_REPORTING)
     Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INSTANTIATORS,
                          aValue);
 #endif // defined(MOZ_TELEMETRY_REPORTING)
+#if defined(MOZ_CRASHREPORTER)
     CrashReporter::
       AnnotateCrashReport(NS_LITERAL_CSTRING("AccessibilityClient"),
                           NS_ConvertUTF16toUTF8(aValue));
+#endif // defined(MOZ_CRASHREPORTER)
   }
 }
 
 static void
 GatherInstantiatorTelemetry(nsIFile* aClientExe)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   nsString value;
   nsresult rv = aClientExe->GetLeafName(value);
   if (NS_SUCCEEDED(rv)) {
     AppendVersionInfo(aClientExe, value);
   }
 
-  nsCOMPtr<nsIFile> ref(aClientExe);
   nsCOMPtr<nsIRunnable> runnable(
     NS_NewRunnableFunction("a11y::AccumulateInstantiatorTelemetry",
-                           [ref, value]() -> void {
-                             AccumulateInstantiatorTelemetry(ref, value);
+                           [value]() -> void {
+                             AccumulateInstantiatorTelemetry(value);
                            }));
 
   // Now that we've (possibly) obtained version info, send the resulting
   // string back to the main thread to accumulate in telemetry.
   NS_DispatchToMainThread(runnable);
 }
 
+#endif // defined(MOZ_TELEMETRY_REPORTING) || defined(MOZ_CRASHREPORTER)
+
 void
 a11y::SetInstantiator(const uint32_t aPid)
 {
   nsCOMPtr<nsIFile> clientExe;
   if (!GetInstantiatorExecutable(aPid, getter_AddRefs(clientExe))) {
-#if defined(MOZ_TELEMETRY_REPORTING)
-    AccumulateInstantiatorTelemetry(nullptr, NS_LITERAL_STRING("(Failed to retrieve client image name)"));
-#endif // defined(MOZ_TELEMETRY_REPORTING)
+#if defined(MOZ_TELEMETRY_REPORTING) || defined(MOZ_CRASHREPORTER)
+    AccumulateInstantiatorTelemetry(NS_LITERAL_STRING("(Failed to retrieve client image name)"));
+#endif // defined(MOZ_TELEMETRY_REPORTING) || defined(MOZ_CRASHREPORTER)
     return;
   }
 
+  // Only record the instantiator if it is the first instantiator, or if it does
+  // not match the previous one. Some blocked clients are repeatedly requesting
+  // a11y over and over so we don't want to be spawning countless telemetry
+  // threads.
+  if (gInstantiator) {
+    bool equal;
+    nsresult rv = gInstantiator->Equals(clientExe, &equal);
+    if (NS_SUCCEEDED(rv) && equal) {
+      return;
+    }
+  }
+
   gInstantiator = clientExe;
 
+#if defined(MOZ_TELEMETRY_REPORTING) || defined(MOZ_CRASHREPORTER)
   nsCOMPtr<nsIRunnable> runnable(
     NS_NewRunnableFunction("a11y::GatherInstantiatorTelemetry",
                            [clientExe]() -> void {
                              GatherInstantiatorTelemetry(clientExe);
                            }));
 
   nsCOMPtr<nsIThread> telemetryThread;
-  NS_NewThread(getter_AddRefs(telemetryThread), runnable);
+  NS_NewNamedThread("a11y telemetry", getter_AddRefs(telemetryThread), runnable);
+#endif // defined(MOZ_TELEMETRY_REPORTING) || defined(MOZ_CRASHREPORTER)
 }
 
 bool
 a11y::GetInstantiator(nsIFile** aOutInstantiator)
 {
   if (!gInstantiator) {
     return false;
   }
--- a/browser/base/content/test/static/browser.ini
+++ b/browser/base/content/test/static/browser.ini
@@ -1,20 +1,18 @@
 [DEFAULT]
 # These tests can be prone to intermittent failures on slower systems.
 # Since the specific flavor doesn't matter from a correctness standpoint,
 # just skip the tests on ASAN and debug builds. Also known to be flaky on
 # Linux32 (bug 1172468, bug 1349307), so skip them there as well.
-#
-# Temporarily disable tests on all 32 bit OSes due to OOM failures after
-# landing bug 1373708.
-skip-if = asan || debug || (bits == 32)
+skip-if = asan || debug || (os == 'linux' && bits == 32)
 support-files =
   head.js
 
 [browser_all_files_referenced.js]
+skip-if = (os == 'win' && bits == 32)
 [browser_misused_characters_in_strings.js]
 support-files =
   bug1262648_string_with_newlines.dtd
 [browser_parsable_css.js]
 support-files =
   dummy_page.html
 [browser_parsable_script.js]
--- 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 23.0
+Version 24.0
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-22...release-23
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-23...release-24
 
 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
@@ -101,21 +101,23 @@
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 :root {
   --icon-size: 13px;
 }
 
 :root.theme-light,
 :root .theme-light {
+  --search-overlays-semitransparent: rgba(221, 225, 228, 0.66);
   --popup-shadow-color: #d0d0d0;
 }
 
 :root.theme-dark,
 :root .theme-dark {
+  --search-overlays-semitransparent: rgba(42, 46, 56, 0.66);
   --popup-shadow-color: #5c667b;
 }
 /* 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/>. */
 
 * {
   box-sizing: border-box;
@@ -1131,21 +1133,68 @@ html[dir="rtl"] .arrow svg,
   position: relative;
 }
 
 .sources-panel * {
   -moz-user-select: none;
   user-select: none;
 }
 
+.sources-clear-root {
+  padding: 4px 3px 4px 3px;
+  width: 100%;
+  text-align: start;
+  white-space: nowrap;
+  color: inherit;
+  display: block;
+  position: absolute;
+  top: 0;
+  left: 0;
+  border-bottom: 1px solid var(--theme-splitter-color);
+}
+
+.sources-clear-root i {
+  margin-right: 5px;
+  position: relative;
+}
+
+.sources-clear-root svg {
+  width: 13px;
+  height: 13px;
+}
+
+.theme-dark .sources-clear-root svg {
+  fill: var(--theme-body-color);
+}
+
+.sources-clear-root .home {
+  opacity: 0.5;
+}
+
+.sources-clear-root .breadcrumb svg {
+  width: 5px;
+  top: 2px;
+  position: absolute;
+  margin-right: 5px;
+}
+
+.sources-clear-root-label {
+  margin-left: 5px;
+}
+
+.sources-pane {
+  display: flex;
+  flex: 1;
+  overflow-x: auto;
+  overflow-y: auto;
+}
+
 .sources-list {
   flex: 1;
   display: flex;
-  overflow-x: hidden;
-  overflow-y: auto;
 }
 
 .sources-list .tree:focus {
   outline: none;
 }
 
 .sources-list .managed-tree {
   flex: 1;
@@ -1283,16 +1332,41 @@ html[dir="rtl"] .arrow svg,
   background-color: white;
 }
 
 .tree:not(.object-inspector)
   .tree-node[data-expandable="false"]
   .tree-indent:last-of-type {
   margin-inline-end: 4px;
 }
+
+/*
+  Custom root styles
+*/
+.sources-pane.sources-list-custom-root {
+  display: block;
+  position: relative;
+}
+
+.sources-list-custom-root .sources-pane {
+  display: block;
+}
+
+.sources-list-custom-root .sources-list {
+  position: absolute;
+  top: 26px;
+  right: 0;
+  bottom: 0;
+  left: 0;
+}
+
+/* Removes start margin when a custom root is used */
+.sources-list-custom-root .tree > .tree-node[data-expandable="false"][aria-level="0"] {
+  padding-inline-start: 4px;
+}
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 .outline {
   overflow-y: hidden;
 }
 
@@ -1383,16 +1457,20 @@ html[dir="rtl"] .arrow svg,
   z-index: 1;
   -moz-user-select: none;
   user-select: none;
   height: 25px;
   box-sizing: border-box;
   display: flex;
 }
 
+.theme-dark .outline-footer button {
+    color: var(--theme-body-color);
+}
+
 .outline-footer button.active {
   background: var(--theme-highlight-blue);
   color: #ffffff;
 }
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
@@ -3858,29 +3936,43 @@ html .welcomebox .toggle-button-end.coll
   line-height: 1.5em;
   word-break: break-all;
 }
 
 .result-list li.selected .title {
   color: white;
 }
 
-.result-list.big li.selected .title {
-  color: var(--theme-body-color);
+.result-list.big li.selected {
+  background-color: var(--theme-selection-background);
+  color: white;
+}
+
+.result-list.big li.selected .subtitle {
+  color: white;
+}
+
+.result-list.big li.selected .subtitle .highlight {
+  color: white;
+  font-weight: bold;
 }
 
 .result-list.big li .subtitle {
   word-break: break-all;
   color: var(--theme-body-color-inactive);
 }
 
 .result-list.big li .subtitle {
   line-height: 1.5em;
 }
 
+.theme-dark .result-list.big li.selected .subtitle {
+  color: white;
+}
+
 .theme-dark .result-list.big li .subtitle {
   color: var(--theme-comment-alt);
 }
 
 .search-bar .result-list li.selected .subtitle {
   color: white;
 }
 
@@ -3888,21 +3980,23 @@ html .welcomebox .toggle-button-end.coll
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .theme-dark .result-list {
   background-color: var(--theme-body-background);
 }
 .result-item .title .highlight {
   font-weight: bold;
+  background-color: transparent;
 }
 
 .result-item .subtitle .highlight {
   color: var(--grey-90);
   font-weight: 500;
+  background-color: transparent;
 }
 
 .theme-dark .result-item .title .highlight,
 .theme-dark .result-item .subtitle .highlight {
   color: white;
 }
 
 .loading-indicator {
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -3593,16 +3593,17 @@ function update(state = initialSourcesSt
 function getTextPropsFromAction(action) {
   const { value, sourceId } = action;
 
   if (action.status === "start") {
     return { id: sourceId, loadedState: "loading" };
   } else if (action.status === "error") {
     return { id: sourceId, error: action.error, loadedState: "loaded" };
   }
+
   return {
     text: value.text,
     id: sourceId,
     contentType: value.contentType,
     loadedState: "loaded"
   };
 }
 
@@ -3614,22 +3615,24 @@ function setSourceTextProps(state, actio
   const text = getTextPropsFromAction(action);
   return updateSource(state, text);
 }
 
 function updateSource(state, source) {
   if (!source.id) {
     return state;
   }
+
   const existingSource = state.getIn(["sources", source.id]);
 
   if (existingSource) {
     const updatedSource = existingSource.merge(source);
     return state.setIn(["sources", source.id], updatedSource);
   }
+
   return state.setIn(["sources", source.id], new SourceRecordClass(source));
 }
 
 function removeSourceFromTabList(tabs, url) {
   return tabs.filter(tab => tab != url);
 }
 
 function removeSourcesFromTabList(tabs, urls) {
@@ -4531,300 +4534,16 @@ SearchInput.defaultProps = {
   hasPrefix: false,
   selectedItemId: "",
   size: ""
 };
 exports.default = SearchInput;
 
 /***/ }),
 
-/***/ 1380:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-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.getLibraryFromUrl = getLibraryFromUrl;
-exports.annotateFrames = annotateFrames;
-exports.simplifyDisplayName = simplifyDisplayName;
-exports.formatDisplayName = formatDisplayName;
-exports.formatCopyName = formatCopyName;
-exports.collapseFrames = collapseFrames;
-
-var _utils = __webpack_require__(1366);
-
-var _source = __webpack_require__(1356);
-
-var _lodash = __webpack_require__(2);
-
-function getFrameUrl(frame) {
-  return (0, _lodash.get)(frame, "source.url", "") || "";
-}
-
-const libraryMap = [{
-  label: "Backbone",
-  pattern: /backbone/i
-}, {
-  label: "jQuery",
-  pattern: /jquery/i
-}, {
-  label: "Preact",
-  pattern: /preact/i
-}, {
-  label: "React",
-  pattern: /react/i
-}, {
-  label: "Immutable",
-  pattern: /immutable/i
-}, {
-  label: "Webpack",
-  pattern: /webpack\/bootstrap/i
-}, {
-  label: "Node",
-  pattern: /(^internal\/|^[^.\/]+\.js)/
-}, {
-  label: "Express",
-  pattern: /node_modules\/express/
-}, {
-  label: "Pug",
-  pattern: /node_modules\/pug/
-}, {
-  label: "ExtJS",
-  pattern: /\/ext-all[\.\-]/
-}, {
-  label: "MobX",
-  pattern: /mobx/i
-}, {
-  label: "Underscore",
-  pattern: /underscore/i
-}, {
-  label: "Lodash",
-  pattern: /lodash/i
-}, {
-  label: "Ember",
-  pattern: /ember/i
-}, {
-  label: "Choo",
-  pattern: /choo/i
-}, {
-  label: "VueJS",
-  pattern: /vue\.js/i
-}, {
-  label: "RxJS",
-  pattern: /rxjs/i
-}, {
-  label: "Angular",
-  pattern: /angular/i
-}, {
-  label: "Redux",
-  pattern: /redux/i
-}, {
-  label: "Dojo",
-  pattern: /dojo/i
-}, {
-  label: "Marko",
-  pattern: /marko/i
-}, {
-  label: "NuxtJS",
-  pattern: /[\._]nuxt/i
-}, {
-  label: "Aframe",
-  pattern: /aframe/i
-}, {
-  label: "NextJS",
-  pattern: /[\._]next/i
-}];
-
-function getLibraryFromUrl(frame) {
-  // @TODO each of these fns calls getFrameUrl, just call it once
-  // (assuming there's not more complex logic to identify a lib)
-  const frameUrl = getFrameUrl(frame);
-  const match = (0, _lodash.find)(libraryMap, o => frameUrl.match(o.pattern));
-  return match && match.label;
-}
-
-const displayNameMap = {
-  Babel: {
-    tryCatch: "Async"
-  },
-  Backbone: {
-    "extend/child": "Create Class",
-    ".create": "Create Model"
-  },
-  jQuery: {
-    "jQuery.event.dispatch": "Dispatch Event"
-  },
-  React: {
-    // eslint-disable-next-line max-len
-    "ReactCompositeComponent._renderValidatedComponentWithoutOwnerOrContext/renderedElement<": "Render",
-    _renderValidatedComponentWithoutOwnerOrContext: "Render"
-  },
-  VueJS: {
-    "renderMixin/Vue.prototype._render": "Render"
-  },
-  Webpack: {
-    // eslint-disable-next-line camelcase
-    __webpack_require__: "Bootstrap"
-  }
-};
-
-function mapDisplayNames(frame, library) {
-  const { displayName } = frame;
-  return displayNameMap[library] && displayNameMap[library][displayName] || displayName;
-}
-
-function annotateFrames(frames) {
-  const annotatedFrames = frames.map(annotateFrame);
-  return annotateBabelAsyncFrames(annotatedFrames);
-}
-
-function annotateFrame(frame) {
-  const library = getLibraryFromUrl(frame);
-  if (library) {
-    return _extends({}, frame, { library });
-  }
-
-  return frame;
-}
-
-function annotateBabelAsyncFrames(frames) {
-  const babelFrameIndexes = getBabelFrameIndexes(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");
-
-  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, getFrameUrl(frame)) ? [...accumulator, index] : accumulator, []);
-}
-
-// Decodes an anonymous naming scheme that
-// spider monkey implements based on "Naming Anonymous JavaScript Functions"
-// http://johnjbarton.github.io/nonymous/index.html
-const objectProperty = /([\w\d]+)$/;
-const arrayProperty = /\[(.*?)\]$/;
-const functionProperty = /([\w\d]+)[\/\.<]*?$/;
-const annonymousProperty = /([\w\d]+)\(\^\)$/;
-
-function simplifyDisplayName(displayName) {
-  // if the display name has a space it has already been mapped
-  if (/\s/.exec(displayName)) {
-    return displayName;
-  }
-
-  const scenarios = [objectProperty, arrayProperty, functionProperty, annonymousProperty];
-
-  for (const reg of scenarios) {
-    const match = reg.exec(displayName);
-    if (match) {
-      return match[1];
-    }
-  }
-
-  return displayName;
-}
-
-function formatDisplayName(frame, { shouldMapDisplayName = true } = {}) {
-  let { displayName, library } = frame;
-  if (library && shouldMapDisplayName) {
-    displayName = mapDisplayNames(frame, library);
-  }
-
-  displayName = simplifyDisplayName(displayName);
-  return (0, _utils.endTruncateStr)(displayName, 25);
-}
-
-function formatCopyName(frame) {
-  const displayName = formatDisplayName(frame);
-  const fileName = (0, _source.getFilename)(frame.source);
-  const frameLocation = frame.location.line;
-
-  return `${displayName} (${fileName}#${frameLocation})`;
-}
-
-function collapseFrames(frames) {
-  // We collapse groups of one so that user frames
-  // are not in a group of one
-  function addGroupToList(group, list) {
-    if (!group) {
-      return list;
-    }
-
-    if (group.length > 1) {
-      list.push(group);
-    } else {
-      list = list.concat(group);
-    }
-
-    return list;
-  }
-  const { newFrames, lastGroup } = collapseLastFrames(frames);
-  frames = newFrames;
-  let items = [];
-  let currentGroup = null;
-  let prevItem = null;
-  for (const frame of frames) {
-    const prevLibrary = (0, _lodash.get)(prevItem, "library");
-
-    if (!currentGroup) {
-      currentGroup = [frame];
-    } else if (prevLibrary && prevLibrary == frame.library) {
-      currentGroup.push(frame);
-    } else {
-      items = addGroupToList(currentGroup, items);
-      currentGroup = [frame];
-    }
-
-    prevItem = frame;
-  }
-
-  items = addGroupToList(currentGroup, items);
-  items = addGroupToList(lastGroup, items);
-  return items;
-}
-
-function collapseLastFrames(frames) {
-  const index = (0, _lodash.findIndex)(frames, frame => getFrameUrl(frame).match(/webpack\/bootstrap/i));
-
-  if (index == -1) {
-    return { newFrames: frames, lastGroup: [] };
-  }
-
-  const newFrames = frames.slice(0, index);
-  const lastGroup = frames.slice(index);
-  return { newFrames, lastGroup };
-}
-
-/***/ }),
-
 /***/ 1381:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 /* 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
@@ -5056,16 +4775,17 @@ var _extends = Object.assign || function
 /**
  * Ast reducer
  * @module reducers/ast
  */
 
 exports.initialASTState = initialASTState;
 exports.getSymbols = getSymbols;
 exports.hasSymbols = hasSymbols;
+exports.isSymbolsLoading = isSymbolsLoading;
 exports.isEmptyLineInSource = isEmptyLineInSource;
 exports.getEmptyLines = getEmptyLines;
 exports.getOutOfScopeLocations = getOutOfScopeLocations;
 exports.getPreview = getPreview;
 exports.getSourceMetaData = getSourceMetaData;
 exports.getInScopeLines = getInScopeLines;
 exports.isLineInScope = isLineInScope;
 
@@ -5091,20 +4811,22 @@ function initialASTState() {
     sourceMetaData: I.Map()
   })();
 }
 
 function update(state = initialASTState(), action) {
   switch (action.type) {
     case "SET_SYMBOLS":
       {
-        const { source, symbols } = action;
-        return state.setIn(["symbols", source.id], symbols);
-      }
-
+        const { source } = action;
+        if (action.status === "start") {
+          return state.setIn(["symbols", source.id], { loading: true });
+        }
+        return state.setIn(["symbols", source.id], action.value);
+      }
     case "SET_EMPTY_LINES":
       {
         const { source, emptyLines } = action;
         return state.setIn(["emptyLines", source.id], emptyLines);
       }
 
     case "OUT_OF_SCOPE_LOCATIONS":
       {
@@ -5155,34 +4877,41 @@ function update(state = initialASTState(
       {
         return state;
       }
   }
 }
 
 // NOTE: we'd like to have the app state fully typed
 // https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js#L179-L185
-
-
-const emptySymbols = { variables: [], functions: [] };
 function getSymbols(state, source) {
   if (!source) {
-    return emptySymbols;
-  }
-
-  const symbols = state.ast.getIn(["symbols", source.id]);
-  return symbols || emptySymbols;
+    return null;
+  }
+
+  return state.ast.getIn(["symbols", source.id]) || null;
 }
 
 function hasSymbols(state, source) {
-  if (!source) {
-    return false;
-  }
-
-  return !!state.ast.getIn(["symbols", source.id]);
+  const symbols = getSymbols(state, source);
+
+  if (!symbols) {
+    return false;
+  }
+
+  return !symbols.loading;
+}
+
+function isSymbolsLoading(state, source) {
+  const symbols = getSymbols(state, source);
+  if (!symbols) {
+    return false;
+  }
+
+  return !!symbols.loading;
 }
 
 function isEmptyLineInSource(state, line, selectedSource) {
   const emptyLines = getEmptyLines(state, selectedSource);
   return emptyLines.includes(line);
 }
 
 function getEmptyLines(state, source) {
@@ -6603,16 +6332,22 @@ exports.setEmptyLines = setEmptyLines;
 exports.setOutOfScopeLocations = setOutOfScopeLocations;
 
 var _selectors = __webpack_require__(3590);
 
 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 sourceRecord = (0, _selectors.getSource)(getState(), sourceId);
     if (!sourceRecord) {
       return;
     }
 
     const source = sourceRecord.toJS();
@@ -6624,34 +6359,36 @@ function setSourceMetaData(sourceId) {
     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 sourceRecord = (0, _selectors.getSource)(getState(), sourceId);
     if (!sourceRecord) {
       return;
     }
 
     const source = sourceRecord.toJS();
     if (!source.text || source.isWasm || (0, _selectors.hasSymbols)(getState(), source)) {
       return;
     }
 
-    const symbols = await (0, _parser.getSymbols)(source.id);
-    dispatch({ type: "SET_SYMBOLS", source, symbols });
+    await dispatch({
+      type: "SET_SYMBOLS",
+      source,
+      [_promise.PROMISE]: (0, _parser.getSymbols)(source.id)
+    });
+
     dispatch(setEmptyLines(sourceId));
     dispatch(setSourceMetaData(sourceId));
   };
 }
 
 function setEmptyLines(sourceId) {
   return async ({ dispatch, getState }) => {
     const sourceRecord = (0, _selectors.getSource)(getState(), sourceId);
@@ -8027,17 +7764,17 @@ function findClosestScope(functions, loc
       return found;
     }
 
     return currNode;
   }, null);
 }
 
 function getASTLocation(source, symbols, location) {
-  if (source.isWasm) {
+  if (source.isWasm || !symbols || symbols.loading) {
     return { name: undefined, offset: location };
   }
 
   const functions = [...symbols.functions];
 
   const scope = findClosestScope(functions, location);
   if (scope) {
     // we only record the line, but at some point we may
@@ -9557,30 +9294,31 @@ async function loadSource(source, { sour
 }
 
 /**
  * @memberof actions/sources
  * @static
  */
 function loadSourceText(source) {
   return async ({ dispatch, getState, client, sourceMaps }) => {
-    const telemetryStart = performance.now();
-    const deferred = (0, _defer2.default)();
+    const id = source.get("id");
 
     // Fetch the source text only once.
+    if (requests.has(id)) {
+      return requests.get(id);
+    }
+
     if ((0, _source.isLoaded)(source)) {
-      return Promise.resolve(source);
-    }
-
-    const id = source.get("id");
-    if ((0, _source.isLoading)(source) || requests.has(id)) {
-      return requests.get(id);
-    }
-
+      return Promise.resolve();
+    }
+
+    const telemetryStart = performance.now();
+    const deferred = (0, _defer2.default)();
     requests.set(id, deferred.promise);
+
     try {
       await dispatch({
         type: "LOAD_SOURCE_TEXT",
         sourceId: id,
         [_promise.PROMISE]: loadSource(source, { sourceMaps, client })
       });
     } catch (e) {
       deferred.resolve();
@@ -10431,29 +10169,29 @@ Object.defineProperty(exports, "__esModu
 });
 
 var _react = __webpack_require__(0);
 
 var _react2 = _interopRequireDefault(_react);
 
 var _lodash = __webpack_require__(2);
 
-var _frame = __webpack_require__(1380);
+var _frames = __webpack_require__(3605);
 
 __webpack_require__(1320);
 
 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/>. */
 
 function getFunctionName(func) {
   const name = func.userDisplayName || func.displayName || func.name;
-  return (0, _frame.simplifyDisplayName)(name);
+  return (0, _frames.simplifyDisplayName)(name);
 }
 
 class PreviewFunction extends _react.Component {
   renderFunctionName(func) {
     const name = getFunctionName(func);
     return _react2.default.createElement(
       "span",
       { className: "function-name" },
@@ -11307,32 +11045,32 @@ var _react2 = _interopRequireDefault(_re
 var _classnames = __webpack_require__(175);
 
 var _classnames2 = _interopRequireDefault(_classnames);
 
 var _Svg = __webpack_require__(1359);
 
 var _Svg2 = _interopRequireDefault(_Svg);
 
-var _frame = __webpack_require__(1380);
+var _frames = __webpack_require__(3605);
 
 var _source = __webpack_require__(1356);
 
 var _FrameMenu = __webpack_require__(1454);
 
 var _FrameMenu2 = _interopRequireDefault(_FrameMenu);
 
 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/>. */
 
 function FrameTitle({ frame, options }) {
-  const displayName = (0, _frame.formatDisplayName)(frame, options);
+  const displayName = (0, _frames.formatDisplayName)(frame, options);
   return _react2.default.createElement(
     "div",
     { className: "title" },
     displayName
   );
 }
 
 function FrameLocation({ frame }) {
@@ -15522,27 +15260,29 @@ const { isDevelopment } = __webpack_requ
 
 const svg = {
   "angle-brackets": __webpack_require__(347),
   angular: __webpack_require__(247),
   arrow: __webpack_require__(348),
   babel: __webpack_require__(3595),
   backbone: __webpack_require__(997),
   blackBox: __webpack_require__(349),
+  breadcrumb: __webpack_require__(3603),
   breakpoint: __webpack_require__(350),
   "column-breakpoint": __webpack_require__(998),
   "case-match": __webpack_require__(351),
   choo: __webpack_require__(1290),
   close: __webpack_require__(352),
   coffeescript: __webpack_require__(2250),
   dojo: __webpack_require__(806),
   domain: __webpack_require__(353),
   file: __webpack_require__(354),
   folder: __webpack_require__(355),
   globe: __webpack_require__(356),
+  home: __webpack_require__(3604),
   javascript: __webpack_require__(2251),
   jquery: __webpack_require__(999),
   underscore: __webpack_require__(1117),
   lodash: __webpack_require__(1118),
   ember: __webpack_require__(1119),
   vuejs: __webpack_require__(1174),
   "magnifying-glass": __webpack_require__(357),
   "arrow-up": __webpack_require__(919),
@@ -16943,16 +16683,24 @@ class Outline extends _react.Component {
 
     return _react2.default.createElement(
       "div",
       { className: "outline-pane-info" },
       placeholderMessage
     );
   }
 
+  renderLoading() {
+    return _react2.default.createElement(
+      "div",
+      { className: "outline-pane-info" },
+      L10N.getStr("loadingText")
+    );
+  }
+
   renderFunction(func) {
     const { name, location, parameterNames } = func;
 
     return _react2.default.createElement(
       "li",
       {
         key: `${name}:${location.start.line}:${location.start.column}`,
         className: "outline-list__element",
@@ -17041,19 +16789,20 @@ class Outline extends _react.Component {
           L10N.getStr("outline.sortLabel")
         )
       )
     );
   }
 
   render() {
     const { symbols } = this.props;
-
+    if (!symbols || symbols.loading) {
+      return this.renderLoading();
+    }
     const symbolsToDisplay = symbols.functions.filter(func => func.name != "anonymous");
-
     return _react2.default.createElement(
       "div",
       { className: "outline" },
       symbolsToDisplay.length > 0 ? this.renderFunctions(symbols.functions) : this.renderPlaceholder()
     );
   }
 }
 
@@ -17190,42 +16939,68 @@ class SourcesTree extends _react.Compone
         projectRoot,
         uncollapsedTree,
         sourceTree
       }));
     }
   }
 
   render() {
-    const expanded = this.props.expanded;
+    const { expanded, projectRoot } = this.props;
     const {
       focusedItem,
       highlightItems,
       listItems,
       parentMap,
       sourceTree
     } = this.state;
 
     const onExpand = (item, expandedState) => {
       this.props.setExpandedState(expandedState);
     };
 
     const onCollapse = (item, expandedState) => {
       this.props.setExpandedState(expandedState);
     };
 
+    const isCustomRoot = projectRoot !== "";
+    let roots = () => sourceTree.contents;
+
+    let clearProjectRootButton = null;
+
+    // The "sourceTree.contents[0]" check ensures that there are contents
+    // A custom root with no existing sources will be ignored
+    if (isCustomRoot && sourceTree.contents[0]) {
+      clearProjectRootButton = _react2.default.createElement(
+        "button",
+        {
+          className: "sources-clear-root",
+          onClick: () => this.props.clearProjectDirectoryRoot(),
+          title: L10N.getStr("removeDirectoryRoot.label")
+        },
+        _react2.default.createElement(_Svg2.default, { name: "home" }),
+        _react2.default.createElement(_Svg2.default, { name: "breadcrumb", "class": true }),
+        _react2.default.createElement(
+          "span",
+          { className: "sources-clear-root-label" },
+          sourceTree.contents[0].name
+        )
+      );
+      roots = () => sourceTree.contents[0].contents;
+    }
+
     const isEmpty = sourceTree.contents.length === 0;
     const treeProps = {
       autoExpandAll: false,
       autoExpandDepth: expanded ? 0 : 1,
       expanded,
       getChildren: item => (0, _sourcesTree.nodeHasChildren)(item) ? item.contents : [],
       getParent: item => parentMap.get(item),
       getPath: this.getPath,
-      getRoots: () => sourceTree.contents,
+      getRoots: roots,
       highlightItems,
       itemHeight: 21,
       key: isEmpty ? "empty" : "full",
       listItems,
       onCollapse,
       onExpand,
       onFocus: this.focusItem,
       renderItem: this.renderItem
@@ -17244,18 +17019,31 @@ class SourcesTree extends _react.Compone
     const onKeyDown = e => {
       if (e.keyCode === 13 && focusedItem) {
         this.selectItem(focusedItem);
       }
     };
 
     return _react2.default.createElement(
       "div",
-      { className: "sources-list", onKeyDown: onKeyDown },
-      tree
+      {
+        className: (0, _classnames2.default)("sources-pane", {
+          "sources-list-custom-root": isCustomRoot
+        })
+      },
+      isCustomRoot ? _react2.default.createElement(
+        "div",
+        { className: "sources-clear-root-container" },
+        clearProjectRootButton
+      ) : null,
+      _react2.default.createElement(
+        "div",
+        { className: "sources-list", onKeyDown: onKeyDown },
+        tree
+      )
     );
   }
 }
 
 // Actions
 
 var _initialiseProps = function () {
   this.focusItem = item => {
@@ -17277,26 +17065,26 @@ var _initialiseProps = function () {
     if (typeof obj !== "undefined" && sources.has(obj) && sources.get(obj).get("isBlackBoxed")) {
       blackBoxedPart = "update";
     }
 
     return `${item.path}/${item.name}/${blackBoxedPart}`;
   };
 
   this.getIcon = (sources, item, depth) => {
-    const { debuggeeUrl } = this.props;
+    const { debuggeeUrl, projectRoot } = this.props;
 
     if (item.path === "/Webpack") {
       return _react2.default.createElement(_Svg2.default, { name: "webpack" });
     }
     if (item.path === "/Angular") {
       return _react2.default.createElement(_Svg2.default, { name: "angular" });
     }
 
-    if (depth === 0) {
+    if (depth === 0 && projectRoot === "") {
       return _react2.default.createElement("img", {
         className: (0, _classnames2.default)("domain", {
           debuggee: debuggeeUrl && debuggeeUrl.includes(item.name)
         })
       });
     }
 
     if (!(0, _sourcesTree.nodeHasChildren)(item)) {
@@ -17368,16 +17156,17 @@ var _initialiseProps = function () {
   };
 
   this.renderItem = (item, depth, focused, _, expanded, { setExpanded }) => {
     const arrow = (0, _sourcesTree.nodeHasChildren)(item) ? _react2.default.createElement("img", {
       className: (0, _classnames2.default)("arrow", {
         expanded: expanded
       })
     }) : _react2.default.createElement("i", { className: "no-arrow" });
+
     const { sources } = this.props;
     const icon = this.getIcon(sources, item, depth);
 
     return _react2.default.createElement(
       "div",
       {
         className: (0, _classnames2.default)("node", { focused }),
         key: item.path,
@@ -24045,17 +23834,17 @@ var _Group2 = _interopRequireDefault(_Gr
 var _WhyPaused = __webpack_require__(1604);
 
 var _WhyPaused2 = _interopRequireDefault(_WhyPaused);
 
 var _actions = __webpack_require__(1354);
 
 var _actions2 = _interopRequireDefault(_actions);
 
-var _frame = __webpack_require__(1380);
+var _frames = __webpack_require__(3605);
 
 var _clipboard = __webpack_require__(1388);
 
 var _selectors = __webpack_require__(3590);
 
 __webpack_require__(1338);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -24072,17 +23861,17 @@ class Frames extends _react.Component {
     this.toggleFramesDisplay = () => {
       this.setState(prevState => ({
         showAllFrames: !prevState.showAllFrames
       }));
     };
 
     this.copyStackTrace = () => {
       const { frames } = this.props;
-      const framesToCopy = frames.map(f => (0, _frame.formatCopyName)(f)).join("\n");
+      const framesToCopy = frames.map(f => (0, _frames.formatCopyName)(f)).join("\n");
       (0, _clipboard.copyToTheClipboard)(framesToCopy);
     };
 
     this.toggleFrameworkGrouping = () => {
       const { toggleFrameworkGrouping, frameworkGroupingOn } = this.props;
       toggleFrameworkGrouping(!frameworkGroupingOn);
     };
 
@@ -24098,17 +23887,17 @@ class Frames extends _react.Component {
   }
 
   collapseFrames(frames) {
     const { frameworkGroupingOn } = this.props;
     if (!frameworkGroupingOn) {
       return frames;
     }
 
-    return (0, _frame.collapseFrames)(frames);
+    return (0, _frames.collapseFrames)(frames);
   }
 
   truncateFrames(frames) {
     const numFramesToShow = this.state.showAllFrames ? frames.length : NUM_FRAMES_SHOWN;
 
     return frames.slice(0, numFramesToShow);
   }
 
@@ -24219,17 +24008,17 @@ var _react2 = _interopRequireDefault(_re
 var _classnames = __webpack_require__(175);
 
 var _classnames2 = _interopRequireDefault(_classnames);
 
 var _Svg = __webpack_require__(1359);
 
 var _Svg2 = _interopRequireDefault(_Svg);
 
-var _frame = __webpack_require__(1380);
+var _frames = __webpack_require__(3605);
 
 var _FrameMenu = __webpack_require__(1454);
 
 var _FrameMenu2 = _interopRequireDefault(_FrameMenu);
 
 __webpack_require__(1336);
 
 var _Frame = __webpack_require__(1453);
@@ -24242,17 +24031,17 @@ var _Badge2 = _interopRequireDefault(_Ba
 
 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/>. */
 
 function FrameLocation({ frame }) {
-  const library = frame.library || (0, _frame.getLibraryFromUrl)(frame);
+  const library = frame.library || (0, _frames.getLibraryFromUrl)(frame);
   if (!library) {
     return null;
   }
 
   return _react2.default.createElement(
     "div",
     { className: "location" },
     library,
@@ -24317,17 +24106,17 @@ class Group extends _react.Component {
         toggleBlackBox: toggleBlackBox,
         toggleFrameworkGrouping: toggleFrameworkGrouping
       }))
     );
   }
 
   renderDescription() {
     const frame = this.props.group[0];
-    const displayName = (0, _frame.formatDisplayName)(frame);
+    const displayName = (0, _frames.formatDisplayName)(frame);
     return _react2.default.createElement(
       "li",
       {
         key: frame.id,
         className: (0, _classnames2.default)("group"),
         onClick: this.toggleFrames,
         tabIndex: 0
       },
@@ -27054,17 +26843,23 @@ function reverseStepOut() {
  * not at an async expression.
  */
 function hasAwait(source, pauseLocation) {
   const { line, column } = pauseLocation;
   if (!source.text) {
     return false;
   }
 
-  const snippet = source.text.split("\n")[line - 1].slice(column - 50, column + 50);
+  const lineText = source.text.split("\n")[line - 1];
+
+  if (!lineText) {
+    return false;
+  }
+
+  const snippet = lineText.slice(column - 50, column + 50);
 
   return !!snippet.match(/(yield|await)/);
 }
 
 /**
  * @memberOf actions/pause
  * @static
  * @param stepType
@@ -27074,17 +26869,17 @@ function astCommand(stepType) {
   return async ({ dispatch, getState, sourceMaps }) => {
     if (!_prefs.features.asyncStepping) {
       return dispatch(command(stepType));
     }
 
     if (stepType == "stepOver") {
       // This type definition is ambiguous:
       const frame = (0, _selectors.getTopFrame)(getState());
-      const source = (0, _selectors.getSelectedSource)(getState()).toJS();
+      const source = (0, _selectors.getSource)(getState(), frame.location.sourceId);
 
       if (source && hasAwait(source, frame.location)) {
         const nextLocation = await (0, _parser.getNextStep)(source.id, frame.location);
         if (nextLocation) {
           await dispatch((0, _breakpoints.addHiddenBreakpoint)(nextLocation));
           return dispatch(command("resume"));
         }
       }
@@ -27105,17 +26900,17 @@ function astCommand(stepType) {
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.findBestMatchExpression = findBestMatchExpression;
 /* 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 findBestMatchExpression(symbols, tokenPos, token) {
+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;
 
     if (overlaps) {
       return expression;
     }
@@ -28076,18 +27871,23 @@ class QuickOpenModal extends _react.Comp
 
     this.isShortcutQuery = () => this.props.searchType === "shortcuts";
 
     this.isSourcesQuery = () => this.props.searchType === "sources";
 
     this.isSourceSearch = () => this.isSourcesQuery() || this.isGotoSourceQuery();
 
     this.renderHighlight = (candidateString, query, name) => {
-      const html = _fuzzaldrinPlus2.default.wrap(candidateString, query);
-
+      const options = {
+        wrap: {
+          tagOpen: '<mark class="highlight">',
+          tagClose: "</mark>"
+        }
+      };
+      const html = _fuzzaldrinPlus2.default.wrap(candidateString, query, options);
       return _react2.default.createElement("div", { dangerouslySetInnerHTML: { __html: html } });
     };
 
     this.highlightMatching = (query, results) => {
       let newQuery = query;
       if (newQuery === "") {
         return results;
       }
@@ -30645,17 +30445,17 @@ var _extends = Object.assign || function
                                                                                                                                                                                                                                                                    * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 exports.formatCallStackFrames = formatCallStackFrames;
 
 var _sources = __webpack_require__(1369);
 
 var _pause = __webpack_require__(1394);
 
-var _frame = __webpack_require__(1380);
+var _frames = __webpack_require__(3605);
 
 var _devtoolsSourceMap = __webpack_require__(1360);
 
 var _lodash = __webpack_require__(2);
 
 var _reselect = __webpack_require__(993);
 
 function getLocation(frame, isGeneratedSource) {
@@ -30677,17 +30477,17 @@ function appendSource(sources, frame, se
 
 function formatCallStackFrames(frames, sources, selectedSource) {
   if (!frames) {
     return null;
   }
 
   const formattedFrames = frames.filter(frame => getSourceForFrame(sources, frame)).map(frame => appendSource(sources, frame, selectedSource)).filter(frame => !(0, _lodash.get)(frame, "source.isBlackBoxed"));
 
-  return (0, _frame.annotateFrames)(formattedFrames);
+  return (0, _frames.annotateFrames)(formattedFrames);
 }
 
 const getCallStackFrames = exports.getCallStackFrames = (0, _reselect.createSelector)(_pause.getFrames, _sources.getSources, _sources.getSelectedSource, formatCallStackFrames);
 
 /***/ }),
 
 /***/ 178:
 /***/ (function(module, exports, __webpack_require__) {
@@ -30802,26 +30602,26 @@ function getOutOfScopeLines(outOfScopeLo
 
   return (0, _lodash.uniq)((0, _lodash.flatMap)(outOfScopeLocations, location => (0, _lodash.range)(location.start.line, location.end.line)));
 } /* 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 setInScopeLines() {
   return ({ dispatch, getState }) => {
-    const source = (0, _selectors.getSelectedSource)(getState());
+    const sourceRecord = (0, _selectors.getSelectedSource)(getState());
     const outOfScopeLocations = (0, _selectors.getOutOfScopeLocations)(getState());
 
-    if (!source || !source.get("text")) {
-      return;
-    }
-
-    const linesOutOfScope = getOutOfScopeLines(outOfScopeLocations, source.toJS());
-
-    const sourceNumLines = (0, _source.getSourceLineCount)(source.toJS());
+    if (!sourceRecord || !sourceRecord.text) {
+      return;
+    }
+
+    const linesOutOfScope = getOutOfScopeLines(outOfScopeLocations);
+
+    const sourceNumLines = (0, _source.getSourceLineCount)(sourceRecord);
     const sourceLines = (0, _lodash.range)(1, sourceNumLines + 1);
 
     const inScopeLines = !linesOutOfScope ? sourceLines : (0, _lodash.without)(sourceLines, ...linesOutOfScope);
 
     dispatch({
       type: "IN_SCOPE_LINES",
       lines: inScopeLines
     });
@@ -30941,17 +30741,16 @@ function isInvalidTarget(target) {
   // exclude codemirror elements that are not tokens
   const invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0;
 
   return invalidTarget || invalidToken || invaildType;
 }
 
 function updatePreview(target, editor) {
   return ({ dispatch, getState, client, sourceMaps }) => {
-    const tokenText = target.innerText ? target.innerText.trim() : "";
     const tokenPos = (0, _editor.getTokenLocation)(editor.codeMirror, target);
     const cursorPos = target.getBoundingClientRect();
     const preview = (0, _selectors.getPreview)(getState());
 
     if ((0, _selectors.getCanRewind)(getState())) {
       return;
     }
 
@@ -30975,20 +30774,20 @@ function updatePreview(target, editor) {
     if (!(0, _selectors.isLineInScope)(getState(), tokenPos.line)) {
       return;
     }
 
     const source = (0, _selectors.getSelectedSource)(getState());
     const symbols = (0, _selectors.getSymbols)(getState(), source.toJS());
 
     let match;
-    if (!symbols || symbols.identifiers.length > 0) {
-      match = (0, _ast.findBestMatchExpression)(symbols, tokenPos, tokenText);
-    } else {
+    if (!symbols || symbols.loading) {
       match = (0, _getExpression.getExpressionFromCoords)(editor.codeMirror, tokenPos);
+    } else {
+      match = (0, _ast.findBestMatchExpression)(symbols, tokenPos);
     }
 
     if (!match || !match.expression) {
       return;
     }
 
     const { expression, location } = match;
     dispatch(setPreview(expression, location, tokenPos, cursorPos));
@@ -31285,25 +31084,25 @@ var _extends = Object.assign || function
                                                                                                                                                                                                                                                                    * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 exports.getScope = getScope;
 
 var _getVariables = __webpack_require__(1765);
 
 var _utils = __webpack_require__(1766);
 
-var _frame = __webpack_require__(1380);
+var _frames = __webpack_require__(3605);
 
 function getScopeTitle(type, scope) {
   if (type === "block" && scope.block && scope.block.displayName) {
     return scope.block.displayName;
   }
 
   if (type === "function" && scope.function) {
-    return scope.function.displayName ? (0, _frame.simplifyDisplayName)(scope.function.displayName) : L10N.getStr("anonymous");
+    return scope.function.displayName ? (0, _frames.simplifyDisplayName)(scope.function.displayName) : L10N.getStr("anonymous");
   }
   return L10N.getStr("scopes.block");
 }
 
 function getScope(scope, selectedFrame, frameScopes, why, scopeIndex) {
   const { type, actor } = scope;
 
   const isLocalScope = scope.actor === frameScopes.actor;
@@ -31884,21 +31683,23 @@ var _extends = Object.assign || function
                                                                                                                                                                                                                                                                    * 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/>. */
 
 /**
  * Redux actions for the sources state
  * @module actions/sources
  */
 
-
-exports.loadSourceMap = loadSourceMap;
 exports.newSource = newSource;
 exports.newSources = newSources;
 
+var _devtoolsSourceMap = __webpack_require__(1360);
+
+var _lodash = __webpack_require__(2);
+
 var _blackbox = __webpack_require__(1802);
 
 var _breakpoints = __webpack_require__(1396);
 
 var _loadSourceText = __webpack_require__(1435);
 
 var _prettyPrint = __webpack_require__(1798);
 
@@ -31914,45 +31715,53 @@ function createOriginalSource(originalUr
     id: sourceMaps.generatedToOriginalId(generatedSource.id, originalUrl),
     isPrettyPrinted: false,
     isWasm: false,
     isBlackBoxed: false,
     loadedState: "unloaded"
   };
 }
 
+function loadSourceMaps(sources) {
+  return async function ({ dispatch, getState, sourceMaps }) {
+    const originalSources = await Promise.all(sources.map(source => dispatch(loadSourceMap(source.id))));
+
+    await dispatch(newSources((0, _lodash.flatten)(originalSources)));
+  };
+}
+
 /**
  * @memberof actions/sources
  * @static
  */
-function loadSourceMap(generatedSource) {
+function loadSourceMap(sourceId) {
   return async function ({ dispatch, getState, sourceMaps }) {
-    let urls;
+    const source = (0, _selectors.getSource)(getState(), sourceId).toJS();
+
+    if (!(0, _devtoolsSourceMap.isGeneratedId)(sourceId) || !source.sourceMapURL) {
+      return;
+    }
+
+    let urls = null;
     try {
-      urls = await sourceMaps.getOriginalURLs(generatedSource);
+      urls = await sourceMaps.getOriginalURLs(source);
     } catch (e) {
       console.error(e);
-      urls = null;
-    }
+    }
+
     if (!urls) {
       // If this source doesn't have a sourcemap, enable it for pretty printing
       dispatch({
         type: "UPDATE_SOURCE",
-        source: _extends({}, generatedSource, { sourceMapURL: "" })
-      });
-      return;
-    }
-
-    const originalSources = urls.map(url => createOriginalSource(url, generatedSource, sourceMaps));
-
-    // TODO: check if this line is really needed, it introduces
-    // a lot of lag to the application.
-    const generatedSourceRecord = (0, _selectors.getSource)(getState(), generatedSource.id);
-    await dispatch((0, _loadSourceText.loadSourceText)(generatedSourceRecord));
-    dispatch(newSources(originalSources));
+        source: _extends({}, source, { sourceMapURL: "" })
+      });
+      return;
+    }
+
+    return urls.map(url => createOriginalSource(url, source, sourceMaps));
   };
 }
 
 // If a request has been made to show this source, go ahead and
 // select it.
 function checkSelectedSource(sourceId) {
   return async ({ dispatch, getState }) => {
     const source = (0, _selectors.getSource)(getState(), sourceId).toJS();
@@ -32019,36 +31828,37 @@ function restoreBlackBoxedSources(source
 function newSource(source) {
   return async ({ dispatch }) => {
     await dispatch(newSources([source]));
   };
 }
 
 function newSources(sources) {
   return async ({ dispatch, getState }) => {
-    const filteredSources = sources.filter(source => !(0, _selectors.getSource)(getState(), source.id));
+    const filteredSources = sources.filter(source => source && !(0, _selectors.getSource)(getState(), source.id));
 
     if (filteredSources.length == 0) {
       return;
     }
 
     dispatch({
       type: "ADD_SOURCES",
       sources: filteredSources
     });
 
     for (const source of filteredSources) {
       dispatch(checkSelectedSource(source.id));
       dispatch(checkPendingBreakpoints(source.id));
     }
 
-    await Promise.all(filteredSources.map(source => dispatch(loadSourceMap(source))));
+    await dispatch(loadSourceMaps(filteredSources));
+
     // We would like to restore the blackboxed state
     // after loading all states to make sure the correctness.
-    dispatch(restoreBlackBoxedSources(filteredSources));
+    await dispatch(restoreBlackBoxedSources(filteredSources));
   };
 }
 
 /***/ }),
 
 /***/ 1802:
 /***/ (function(module, exports, __webpack_require__) {
 
@@ -34679,43 +34489,48 @@ if (prefs.debuggerPrefsSchemaVersion !==
 
 "use strict";
 
 
 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; };
+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.initialState = initialState;
 exports.getHistory = getHistory;
 exports.getHistoryFrame = getHistoryFrame;
 exports.getHistoryPosition = getHistoryPosition;
+
+var _prefs = __webpack_require__(226);
+
+/**
+ * Breakpoints reducer
+ * @module reducers/replay
+ */
 function initialState() {
   return {
     history: [],
     position: -1
   };
-} /* This Source Code Form is subject to the terms of the Mozilla Public
-   * License, v. 2.0. If a copy of the MPL was not distributed with this
-   * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-
-/**
- * Breakpoints reducer
- * @module reducers/replay
- */
-
+}
 
 const defaultFrameScopes = {
   original: {},
   generated: {}
 };
 
 function update(state = initialState(), action) {
+  if (!_prefs.features.replay) {
+    return state;
+  }
+
   switch (action.type) {
     case "TRAVEL_TO":
       {
         return _extends({}, state, { position: action.position });
       }
 
     case "ADD_SCOPES":
       {
@@ -34745,16 +34560,21 @@ function update(state = initialState(), 
 
   return state;
 }
 
 function addScopes(state, action) {
   const { frame, status, value } = action;
   const selectedFrameId = frame.id;
   const instance = state.history[state.position];
+
+  if (!instance) {
+    return state;
+  }
+
   const pausedInst = instance.paused;
 
   const generated = _extends({}, pausedInst.frameScopes.generated, {
     [selectedFrameId]: {
       pending: status !== "done",
       scope: value
     }
   });
@@ -34769,16 +34589,21 @@ function addScopes(state, action) {
   history[state.position] = _extends({}, instance, { paused: newPaused });
   return _extends({}, state, { history });
 }
 
 function mapScopes(state, action) {
   const { frame, status, value } = action;
   const selectedFrameId = frame.id;
   const instance = state.history[state.position];
+
+  if (!instance) {
+    return state;
+  }
+
   const pausedInst = instance.paused;
 
   const original = _extends({}, pausedInst.frameScopes.original, {
     [selectedFrameId]: {
       pending: status !== "done",
       scope: value
     }
   });
@@ -34795,16 +34620,17 @@ function mapScopes(state, action) {
 }
 
 function evaluateExpression(state, action) {
   const { input, value } = action;
   const instance = state.history[state.position];
   if (!instance) {
     return state;
   }
+
   const prevExpressions = instance.expressions || [];
   const expression = { input, value };
   const expressions = [...prevExpressions, expression];
 
   const history = [...state.history];
   history[state.position] = _extends({}, instance, { expressions });
   return _extends({}, state, { history });
 }
@@ -37574,23 +37400,472 @@ module.exports = "<!-- This Source Code 
 
 /***/ 360:
 /***/ (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 viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.5 8.5V14a.5.5 0 1 1-1 0V8.5H2a.5.5 0 0 1 0-1h5.5V2a.5.5 0 0 1 1 0v5.5H14a.5.5 0 1 1 0 1H8.5z\" fill-rule=\"evenodd\"></path></svg>"
 
 /***/ }),
 
+/***/ 3603:
+/***/ (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:xlink=\"http://www.w3.org/1999/xlink\"><defs><linearGradient id=\"b\"><stop offset=\"0\" stop-color=\"#9a9aba\"></stop><stop offset=\"1\" stop-color=\"#a6a6c2\"></stop></linearGradient><linearGradient id=\"a\"><stop offset=\"0\" stop-color=\"#8e8eb2\"></stop><stop offset=\"1\" stop-color=\"#9a9aba\"></stop></linearGradient><linearGradient x1=\"3.616\" y1=\"3.893\" x2=\"1.285\" y2=\"-.757\" id=\"d\" xlink:href=\"#a\" gradientUnits=\"userSpaceOnUse\" gradientTransform=\"matrix(1 0 0 .8684 0 1046.257)\"></linearGradient><linearGradient x1=\"2.232\" y1=\"4.162\" x2=\".629\" y2=\".966\" id=\"c\" xlink:href=\"#b\" gradientUnits=\"userSpaceOnUse\" gradientTransform=\"matrix(1 0 0 .8684 0 1046.257)\"></linearGradient></defs><path d=\"M.2 1045.562l4.6 3.3-4.6 3.3 2-3.3z\" fill=\"url(#c)\" stroke=\"url(#d)\" stroke-width=\".4\" stroke-linejoin=\"round\" transform=\"translate(0 -1045.362)\"></path></svg>"
+
+/***/ }),
+
+/***/ 3604:
+/***/ (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\" viewBox=\"0 0 16 16\"><path d=\"M15.7 7.3l-7-7c-.4-.4-1-.4-1.4 0l-7 7c-.4.4-.4 1 0 1.4.4.4 1 .4 1.4 0l.3-.3V13c0 1.7 1.3 3 3 3h6c1.7 0 3-1.3 3-3V8.4l.3.3c.2.2.4.3.7.3.3 0 .5-.1.7-.3.4-.4.4-1 0-1.4zM8 11.5c0-.3.2-.5.5-.5s.5.2.5.5-.2.5-.5.5-.5-.2-.5-.5zm4 1.5c0 .6-.4 1-1 1h-1V9c0-.6-.4-1-1-1H7c-.6 0-1 .4-1 1v5H5c-.6 0-1-.4-1-1V6.4l4-4 4 4V13z\"></path></svg>"
+
+/***/ }),
+
+/***/ 3605:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _annotateFrames = __webpack_require__(3608);
+
+Object.keys(_annotateFrames).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  Object.defineProperty(exports, key, {
+    enumerable: true,
+    get: function () {
+      return _annotateFrames[key];
+    }
+  });
+});
+
+var _collapseFrames = __webpack_require__(3609);
+
+Object.keys(_collapseFrames).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  Object.defineProperty(exports, key, {
+    enumerable: true,
+    get: function () {
+      return _collapseFrames[key];
+    }
+  });
+});
+
+var _displayName = __webpack_require__(3610);
+
+Object.keys(_displayName).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  Object.defineProperty(exports, key, {
+    enumerable: true,
+    get: function () {
+      return _displayName[key];
+    }
+  });
+});
+
+var _getFrameUrl = __webpack_require__(3606);
+
+Object.keys(_getFrameUrl).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  Object.defineProperty(exports, key, {
+    enumerable: true,
+    get: function () {
+      return _getFrameUrl[key];
+    }
+  });
+});
+
+var _getLibraryFromUrl = __webpack_require__(3607);
+
+Object.keys(_getLibraryFromUrl).forEach(function (key) {
+  if (key === "default" || key === "__esModule") return;
+  Object.defineProperty(exports, key, {
+    enumerable: true,
+    get: function () {
+      return _getLibraryFromUrl[key];
+    }
+  });
+});
+
+/***/ }),
+
+/***/ 3606:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.getFrameUrl = getFrameUrl;
+
+var _lodash = __webpack_require__(2);
+
+function getFrameUrl(frame) {
+  return (0, _lodash.get)(frame, "source.url", "") || "";
+} /* 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/>. */
+
+/***/ }),
+
+/***/ 3607:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.getLibraryFromUrl = getLibraryFromUrl;
+
+var _lodash = __webpack_require__(2);
+
+var _getFrameUrl = __webpack_require__(3606);
+
+/* 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 libraryMap = [{
+  label: "Backbone",
+  pattern: /backbone/i
+}, {
+  label: "jQuery",
+  pattern: /jquery/i
+}, {
+  label: "Preact",
+  pattern: /preact/i
+}, {
+  label: "React",
+  pattern: /react/i
+}, {
+  label: "Immutable",
+  pattern: /immutable/i
+}, {
+  label: "Webpack",
+  pattern: /webpack\/bootstrap/i
+}, {
+  label: "Node",
+  pattern: /(^internal\/|^[^.\/]+\.js)/
+}, {
+  label: "Express",
+  pattern: /node_modules\/express/
+}, {
+  label: "Pug",
+  pattern: /node_modules\/pug/
+}, {
+  label: "ExtJS",
+  pattern: /\/ext-all[\.\-]/
+}, {
+  label: "MobX",
+  pattern: /mobx/i
+}, {
+  label: "Underscore",
+  pattern: /underscore/i
+}, {
+  label: "Lodash",
+  pattern: /lodash/i
+}, {
+  label: "Ember",
+  pattern: /ember/i
+}, {
+  label: "Choo",
+  pattern: /choo/i
+}, {
+  label: "VueJS",
+  pattern: /vue\.js/i
+}, {
+  label: "RxJS",
+  pattern: /rxjs/i
+}, {
+  label: "Angular",
+  pattern: /angular/i
+}, {
+  label: "Redux",
+  pattern: /redux/i
+}, {
+  label: "Dojo",
+  pattern: /dojo/i
+}, {
+  label: "Marko",
+  pattern: /marko/i
+}, {
+  label: "NuxtJS",
+  pattern: /[\._]nuxt/i
+}, {
+  label: "Aframe",
+  pattern: /aframe/i
+}, {
+  label: "NextJS",
+  pattern: /[\._]next/i
+}];
+
+function getLibraryFromUrl(frame) {
+  // @TODO each of these fns calls getFrameUrl, just call it once
+  // (assuming there's not more complex logic to identify a lib)
+  const frameUrl = (0, _getFrameUrl.getFrameUrl)(frame);
+  const match = (0, _lodash.find)(libraryMap, o => frameUrl.match(o.pattern));
+  return match && match.label;
+}
+
+/***/ }),
+
+/***/ 3608:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+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.annotateFrames = annotateFrames;
+
+var _lodash = __webpack_require__(2);
+
+var _getFrameUrl = __webpack_require__(3606);
+
+var _getLibraryFromUrl = __webpack_require__(3607);
+
+function annotateFrames(frames) {
+  const annotatedFrames = frames.map(annotateFrame);
+  return annotateBabelAsyncFrames(annotatedFrames);
+}
+
+function annotateFrame(frame) {
+  const library = (0, _getLibraryFromUrl.getLibraryFromUrl)(frame);
+  if (library) {
+    return _extends({}, frame, { library });
+  }
+
+  return frame;
+}
+
+function annotateBabelAsyncFrames(frames) {
+  const babelFrameIndexes = getBabelFrameIndexes(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");
+
+  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";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.collapseFrames = collapseFrames;
+
+var _lodash = __webpack_require__(2);
+
+var _getFrameUrl = __webpack_require__(3606);
+
+/* 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 collapseLastFrames(frames) {
+  const index = (0, _lodash.findIndex)(frames, frame => (0, _getFrameUrl.getFrameUrl)(frame).match(/webpack\/bootstrap/i));
+
+  if (index == -1) {
+    return { newFrames: frames, lastGroup: [] };
+  }
+
+  const newFrames = frames.slice(0, index);
+  const lastGroup = frames.slice(index);
+  return { newFrames, lastGroup };
+}
+
+// eslint-disable-next-line max-len
+function collapseFrames(frames) {
+  // We collapse groups of one so that user frames
+  // are not in a group of one
+  function addGroupToList(group, list) {
+    if (!group) {
+      return list;
+    }
+
+    if (group.length > 1) {
+      list.push(group);
+    } else {
+      list = list.concat(group);
+    }
+
+    return list;
+  }
+  const { newFrames, lastGroup } = collapseLastFrames(frames);
+  frames = newFrames;
+  let items = [];
+  let currentGroup = null;
+  let prevItem = null;
+  for (const frame of frames) {
+    const prevLibrary = (0, _lodash.get)(prevItem, "library");
+
+    if (!currentGroup) {
+      currentGroup = [frame];
+    } else if (prevLibrary && prevLibrary == frame.library) {
+      currentGroup.push(frame);
+    } else {
+      items = addGroupToList(currentGroup, items);
+      currentGroup = [frame];
+    }
+
+    prevItem = frame;
+  }
+
+  items = addGroupToList(currentGroup, items);
+  items = addGroupToList(lastGroup, items);
+  return items;
+}
+
+/***/ }),
+
 /***/ 361:
 /***/ (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 viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M4.525 13.21h-.472c-.574 0-.987-.154-1.24-.463-.253-.31-.38-.882-.38-1.719v-.573c0-.746-.097-1.265-.292-1.557-.196-.293-.51-.44-.945-.44v-.974c.435 0 .75-.146.945-.44.195-.292.293-.811.293-1.556v-.58c0-.833.126-1.404.379-1.712.253-.31.666-.464 1.24-.464h.472v.783h-.179c-.37 0-.628.08-.774.24-.145.159-.218.54-.218 1.141v.383c0 .824-.096 1.432-.287 1.823-.191.39-.516.679-.974.866.458.191.783.482.974.873.191.39.287.998.287 1.823v.382c0 .602.073.982.218 1.142.146.16.404.239.774.239h.18v.783zm9.502-4.752c-.43 0-.744.147-.942.44-.197.292-.296.811-.296 1.557v.573c0 .837-.125 1.41-.376 1.719-.251.309-.664.463-1.237.463h-.478v-.783h.185c.37 0 .628-.08.774-.24.145-.159.218-.539.218-1.14v-.383c0-.825.096-1.433.287-1.823.191-.39.516-.682.974-.873-.458-.187-.783-.476-.974-.866-.191-.391-.287-.999-.287-1.823v-.383c0-.602-.073-.982-.218-1.142-.146-.159-.404-.239-.774-.239h-.185v-.783h.478c.573 0 .986.155 1.237.464.25.308.376.88.376 1.712v.58c0 .673.088 1.174.263 1.503.176.329.5.493.975.493v.974z\" fill-rule=\"evenodd\"></path></svg>"
 
 /***/ }),
 
+/***/ 3610:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.simplifyDisplayName = simplifyDisplayName;
+exports.formatDisplayName = formatDisplayName;
+exports.formatCopyName = formatCopyName;
+
+var _source = __webpack_require__(1356);
+
+var _utils = __webpack_require__(1366);
+
+// Decodes an anonymous naming scheme that
+// spider monkey implements based on "Naming Anonymous JavaScript Functions"
+// http://johnjbarton.github.io/nonymous/index.html
+const objectProperty = /([\w\d]+)$/; /* 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/>. */
+
+// eslint-disable-next-line max-len
+
+const arrayProperty = /\[(.*?)\]$/;
+const functionProperty = /([\w\d]+)[\/\.<]*?$/;
+const annonymousProperty = /([\w\d]+)\(\^\)$/;
+
+function simplifyDisplayName(displayName) {
+  // if the display name has a space it has already been mapped
+  if (/\s/.exec(displayName)) {
+    return displayName;
+  }
+
+  const scenarios = [objectProperty, arrayProperty, functionProperty, annonymousProperty];
+
+  for (const reg of scenarios) {
+    const match = reg.exec(displayName);
+    if (match) {
+      return match[1];
+    }
+  }
+
+  return displayName;
+}
+
+const displayNameMap = {
+  Babel: {
+    tryCatch: "Async"
+  },
+  Backbone: {
+    "extend/child": "Create Class",
+    ".create": "Create Model"
+  },
+  jQuery: {
+    "jQuery.event.dispatch": "Dispatch Event"
+  },
+  React: {
+    // eslint-disable-next-line max-len
+    "ReactCompositeComponent._renderValidatedComponentWithoutOwnerOrContext/renderedElement<": "Render",
+    _renderValidatedComponentWithoutOwnerOrContext: "Render"
+  },
+  VueJS: {
+    "renderMixin/Vue.prototype._render": "Render"
+  },
+  Webpack: {
+    // eslint-disable-next-line camelcase
+    __webpack_require__: "Bootstrap"
+  }
+};
+
+function mapDisplayNames(frame, library) {
+  const { displayName } = frame;
+  return displayNameMap[library] && displayNameMap[library][displayName] || displayName;
+}
+
+function formatDisplayName(frame, { shouldMapDisplayName = true } = {}) {
+  let { displayName, library } = frame;
+  if (library && shouldMapDisplayName) {
+    displayName = mapDisplayNames(frame, library);
+  }
+
+  displayName = simplifyDisplayName(displayName);
+  return (0, _utils.endTruncateStr)(displayName, 25);
+}
+
+function formatCopyName(frame) {
+  const displayName = formatDisplayName(frame);
+  const fileName = (0, _source.getFilename)(frame.source);
+  const frameLocation = frame.location.line;
+
+  return `${displayName} (${fileName}#${frameLocation})`;
+}
+
+/***/ }),
+
 /***/ 362:
 /***/ (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:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 20 16\" stroke=\"none\" fillrule=\"evenodd\"><rect x=\"3\" y=\"10\" width=\"3\" height=\"3\" rx=\"1\"></rect><rect x=\"12\" y=\"3\" width=\"2\" height=\"9\" rx=\"1\"></rect><rect transform=\"translate(13.000000, 7.500000) rotate(60.000000) translate(-13.000000, -7.500000) \" x=\"12\" y=\"3\" width=\"2\" height=\"9\" rx=\"1\"></rect><rect transform=\"translate(13.000000, 7.500000) rotate(-60.000000) translate(-13.000000, -7.500000) \" x=\"12\" y=\"3\" width=\"2\" height=\"9\" rx=\"1\"></rect></svg>"
 
 /***/ }),
 
 /***/ 363:
@@ -39642,9 +39917,9 @@ module.exports = "<!-- This Source Code 
 /***/ 999:
 /***/ (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 version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 32 32\"><path fill=\"#444444\" d=\"M16.232 24.047c-0.15-0.034-0.295-0.081-0.441-0.124-0.037-0.011-0.074-0.022-0.11-0.033-0.143-0.044-0.284-0.090-0.425-0.139-0.019-0.007-0.039-0.014-0.058-0.021-0.126-0.045-0.251-0.091-0.375-0.139-0.035-0.014-0.070-0.027-0.105-0.041-0.136-0.054-0.271-0.11-0.405-0.168-0.027-0.012-0.054-0.024-0.081-0.036-0.115-0.052-0.228-0.105-0.341-0.159-0.033-0.016-0.065-0.031-0.099-0.047-0.089-0.043-0.177-0.090-0.264-0.134-0.059-0.031-0.118-0.060-0.176-0.092-0.107-0.058-0.212-0.117-0.317-0.178-0.035-0.020-0.071-0.038-0.107-0.059-0.139-0.081-0.277-0.166-0.412-0.252-0.037-0.024-0.074-0.050-0.111-0.074-0.099-0.063-0.197-0.128-0.293-0.195-0.032-0.021-0.063-0.045-0.094-0.066-0.093-0.066-0.186-0.132-0.277-0.2-0.042-0.031-0.082-0.062-0.123-0.093-0.084-0.064-0.168-0.129-0.25-0.196-0.037-0.030-0.075-0.060-0.112-0.090-0.105-0.087-0.209-0.173-0.312-0.263-0.011-0.009-0.023-0.018-0.034-0.028-0.111-0.097-0.22-0.197-0.328-0.298-0.031-0.030-0.062-0.059-0.092-0.088-0.080-0.076-0.158-0.153-0.235-0.231-0.031-0.031-0.062-0.061-0.092-0.092-0.098-0.101-0.194-0.203-0.289-0.306-0.005-0.005-0.010-0.010-0.014-0.015-0.1-0.109-0.197-0.221-0.293-0.334-0.026-0.031-0.051-0.060-0.077-0.091-0.071-0.086-0.142-0.173-0.211-0.261-0.026-0.031-0.052-0.064-0.077-0.096-0.083-0.108-0.164-0.215-0.243-0.324-2.197-2.996-2.986-7.129-1.23-10.523l-1.556 1.974c-1.994 2.866-1.746 6.595-0.223 9.64 0.036 0.073 0.074 0.145 0.112 0.217 0.024 0.045 0.046 0.092 0.071 0.137 0.014 0.027 0.030 0.053 0.044 0.079 0.026 0.049 0.053 0.095 0.079 0.142 0.047 0.083 0.096 0.166 0.145 0.249 0.027 0.045 0.055 0.091 0.083 0.136 0.055 0.089 0.111 0.176 0.169 0.264 0.024 0.037 0.047 0.075 0.072 0.111 0.080 0.118 0.161 0.236 0.244 0.353 0.002 0.003 0.005 0.006 0.007 0.009 0.013 0.018 0.028 0.037 0.041 0.056 0.072 0.1 0.147 0.199 0.223 0.296 0.028 0.036 0.056 0.072 0.084 0.107 0.067 0.085 0.136 0.169 0.206 0.253 0.026 0.031 0.052 0.063 0.079 0.094 0.094 0.11 0.189 0.22 0.287 0.328 0.002 0.002 0.004 0.004 0.006 0.005 0.004 0.005 0.008 0.008 0.011 0.013 0.095 0.104 0.193 0.206 0.291 0.307 0.031 0.032 0.062 0.063 0.093 0.094 0.076 0.077 0.154 0.153 0.233 0.228 0.032 0.030 0.063 0.061 0.095 0.091 0.105 0.099 0.211 0.196 0.319 0.291 0.002 0.001 0.003 0.003 0.005 0.004 0.018 0.016 0.038 0.032 0.056 0.047 0.095 0.082 0.192 0.164 0.29 0.245 0.040 0.032 0.080 0.064 0.12 0.096 0.080 0.064 0.16 0.127 0.241 0.189 0.043 0.033 0.086 0.066 0.129 0.098 0.089 0.066 0.18 0.131 0.271 0.194 0.033 0.024 0.065 0.047 0.099 0.070 0.009 0.006 0.018 0.013 0.027 0.019 0.086 0.060 0.175 0.116 0.263 0.174 0.038 0.025 0.075 0.051 0.114 0.076 0.136 0.086 0.273 0.171 0.412 0.253 0.038 0.022 0.076 0.043 0.114 0.064 0.102 0.059 0.205 0.117 0.309 0.174 0.056 0.030 0.114 0.059 0.171 0.088 0.073 0.038 0.147 0.078 0.221 0.115 0.017 0.009 0.035 0.017 0.051 0.025 0.030 0.014 0.060 0.028 0.091 0.044 0.116 0.055 0.233 0.11 0.351 0.163 0.025 0.011 0.049 0.022 0.074 0.033 0.135 0.059 0.271 0.116 0.409 0.17 0.033 0.014 0.066 0.026 0.1 0.039 0.127 0.049 0.256 0.098 0.386 0.143 0.016 0.006 0.032 0.012 0.049 0.017 0.142 0.050 0.286 0.096 0.43 0.141 0.034 0.010 0.069 0.021 0.104 0.031 0.147 0.044 0.293 0.097 0.445 0.125 9.643 1.759 12.444-5.795 12.444-5.795-2.352 3.065-6.528 3.873-10.485 2.974zM12.758 16.231c0.216 0.31 0.456 0.678 0.742 0.927 0.104 0.114 0.213 0.226 0.324 0.336 0.028 0.029 0.057 0.056 0.085 0.084 0.108 0.105 0.217 0.207 0.33 0.307 0.005 0.003 0.009 0.008 0.014 0.012 0.001 0.001 0.002 0.002 0.003 0.003 0.125 0.11 0.255 0.216 0.386 0.319 0.029 0.022 0.058 0.046 0.088 0.069 0.132 0.101 0.266 0.2 0.404 0.295 0.004 0.003 0.008 0.006 0.012 0.009 0.061 0.042 0.123 0.081 0.184 0.122 0.030 0.019 0.058 0.040 0.088 0.058 0.098 0.063 0.198 0.125 0.299 0.183 0.014 0.009 0.028 0.016 0.042 0.024 0.087 0.051 0.176 0.1 0.265 0.148 0.031 0.018 0.063 0.033 0.094 0.049 0.061 0.032 0.123 0.064 0.185 0.096 0.009 0.004 0.019 0.009 0.028 0.012 0.127 0.063 0.255 0.123 0.386 0.18 0.028 0.012 0.057 0.023 0.085 0.035 0.105 0.045 0.21 0.088 0.316 0.129 0.045 0.017 0.091 0.033 0.135 0.050 0.097 0.036 0.193 0.069 0.291 0.101 0.044 0.014 0.087 0.028 0.131 0.042 0.139 0.043 0.276 0.098 0.42 0.122 7.445 1.233 9.164-4.499 9.164-4.499-1.549 2.232-4.55 3.296-7.752 2.465-0.142-0.038-0.282-0.078-0.422-0.122-0.043-0.013-0.084-0.027-0.127-0.041-0.099-0.032-0.197-0.066-0.295-0.102-0.045-0.017-0.089-0.033-0.133-0.050-0.107-0.041-0.213-0.084-0.317-0.128-0.029-0.013-0.058-0.024-0.086-0.036-0.131-0.057-0.261-0.117-0.389-0.18-0.066-0.032-0.13-0.066-0.195-0.099-0.037-0.019-0.075-0.038-0.112-0.058-0.083-0.045-0.165-0.092-0.246-0.139-0.019-0.011-0.040-0.022-0.059-0.033-0.101-0.059-0.2-0.12-0.299-0.182-0.030-0.019-0.060-0.040-0.090-0.060-0.065-0.042-0.13-0.085-0.193-0.128-0.137-0.095-0.271-0.194-0.402-0.294-0.030-0.024-0.061-0.047-0.091-0.071-1.401-1.107-2.512-2.619-3.041-4.334-0.554-1.778-0.434-3.775 0.525-5.395l-1.178 1.663c-1.442 2.075-1.364 4.853-0.239 7.048 0.189 0.368 0.401 0.725 0.638 1.065zM20.606 13.664c0.061 0.023 0.123 0.043 0.185 0.064 0.027 0.008 0.054 0.018 0.082 0.026 0.088 0.027 0.175 0.060 0.265 0.076 4.111 0.794 5.226-2.11 5.523-2.537-0.977 1.406-2.618 1.744-4.632 1.255-0.159-0.039-0.334-0.096-0.488-0.151-0.197-0.070-0.39-0.15-0.579-0.24-0.358-0.172-0.699-0.38-1.015-0.619-1.802-1.367-2.922-3.976-1.746-6.101l-0.637 0.877c-0.85 1.251-0.933 2.805-0.344 4.186 0.622 1.467 1.897 2.617 3.384 3.163z\"></path></svg>"
 
 /***/ })
 
 /******/ });
-});
+});
\ No newline at end of file
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -1348,16 +1348,17 @@ module.exports = isObjectLike;
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.isFunction = isFunction;
 exports.isAwaitExpression = isAwaitExpression;
 exports.isYieldExpression = isYieldExpression;
 exports.isVariable = isVariable;
+exports.isComputedExpression = isComputedExpression;
 exports.getMemberExpression = getMemberExpression;
 exports.getVariables = getVariables;
 
 var _types = __webpack_require__(2268);
 
 var t = _interopRequireWildcard(_types);
 
 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
@@ -1378,16 +1379,21 @@ function isYieldExpression(path) {
   return t.isYieldExpression(node) || t.isYieldExpression(parent.init) || t.isYieldExpression(parent);
 }
 
 function isVariable(path) {
   const node = path.node;
   return t.isVariableDeclaration(node) || isFunction(path) && path.node.params != null && path.node.params.length || t.isObjectProperty(node) && !isFunction(path.node.value);
 }
 
+function isComputedExpression(expression) {
+  return (/^\[/m.test(expression)
+  );
+}
+
 function getMemberExpression(root) {
   function _getMemberExpression(node, expr) {
     if (t.isMemberExpression(node)) {
       expr = [node.property.name].concat(expr);
       return _getMemberExpression(node.object, expr);
     }
 
     if (t.isCallExpression(node)) {
@@ -1581,17 +1587,17 @@ Object.defineProperty(exports, "__esModu
   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.clearSymbols = clearSymbols;
-exports.default = getSymbols;
+exports.getSymbols = getSymbols;
 
 var _flatten = __webpack_require__(706);
 
 var _flatten2 = _interopRequireDefault(_flatten);
 
 var _types = __webpack_require__(2268);
 
 var t = _interopRequireWildcard(_types);
@@ -1843,54 +1849,62 @@ function extractSymbols(sourceId) {
   return symbols;
 }
 
 function extendSnippet(name, expression, path = null, prevPath = null) {
   const computed = path && path.node.computed;
   const prevComputed = prevPath && prevPath.node.computed;
   const prevArray = t.isArrayExpression(prevPath);
   const array = t.isArrayExpression(path);
+  const value = path && path.node.property && path.node.property.extra && path.node.property.extra.raw || "";
 
   if (expression === "") {
     if (computed) {
-      return `[${name}]`;
+      return name === undefined ? `[${value}]` : `[${name}]`;
     }
     return name;
   }
 
   if (computed || array) {
     if (prevComputed || prevArray) {
       return `[${name}]${expression}`;
     }
-    return `[${name}].${expression}`;
+    return `[${name === undefined ? value : name}].${expression}`;
   }
 
   if (prevComputed || prevArray) {
     return `${name}${expression}`;
   }
 
+  if ((0, _helpers.isComputedExpression)(expression) && name !== undefined) {
+    return `${name}${expression}`;
+  }
+
   return `${name}.${expression}`;
 }
 
 function getMemberSnippet(node, expression = "") {
   if (t.isMemberExpression(node)) {
     const name = node.property.name;
-
-    return getMemberSnippet(node.object, extendSnippet(name, expression));
+    const snippet = getMemberSnippet(node.object, extendSnippet(name, expression, { node }));
+    return snippet;
   }
 
   if (t.isCallExpression(node)) {
     return "";
   }
 
   if (t.isThisExpression(node)) {
     return `this.${expression}`;
   }
 
   if (t.isIdentifier(node)) {
+    if ((0, _helpers.isComputedExpression)(expression)) {
+      return `${node.name}${expression}`;
+    }
     return `${node.name}.${expression}`;
   }
 
   return expression;
 }
 
 function getObjectSnippet(path, prevPath, expression = "") {
   if (!path) {
@@ -2048,18 +2062,16 @@ function clearSources() {
 
 "use strict";
 
 
 var _closest = __webpack_require__(1455);
 
 var _getSymbols = __webpack_require__(1457);
 
-var _getSymbols2 = _interopRequireDefault(_getSymbols);
-
 var _ast = __webpack_require__(1375);
 
 var _getScopes = __webpack_require__(2413);
 
 var _getScopes2 = _interopRequireDefault(_getScopes);
 
 var _sources = __webpack_require__(1458);
 
@@ -2087,17 +2099,17 @@ function _interopRequireDefault(obj) { r
  * 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 { workerHandler } = _devtoolsUtils.workerUtils;
 
 self.onmessage = workerHandler({
   getClosestExpression: _closest.getClosestExpression,
   findOutOfScopeLocations: _findOutOfScopeLocations2.default,
-  getSymbols: _getSymbols2.default,
+  getSymbols: _getSymbols.getSymbols,
   getScopes: _getScopes2.default,
   clearSymbols: _getSymbols.clearSymbols,
   clearScopes: _getScopes.clearScopes,
   clearASTs: _ast.clearASTs,
   hasSource: _sources.hasSource,
   setSource: _sources.setSource,
   clearSources: _sources.clearSources,
   isInvalidPauseLocation: _pauseLocation.isInvalidPauseLocation,
@@ -2322,22 +2334,20 @@ var _findIndex2 = _interopRequireDefault
 var _findLastIndex = __webpack_require__(1686);
 
 var _findLastIndex2 = _interopRequireDefault(_findLastIndex);
 
 var _contains = __webpack_require__(1456);
 
 var _getSymbols = __webpack_require__(1457);
 
-var _getSymbols2 = _interopRequireDefault(_getSymbols);
-
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 function findSymbols(source) {
-  const { functions, comments } = (0, _getSymbols2.default)(source);
+  const { functions, comments } = (0, _getSymbols.getSymbols)(source);
   return { functions, comments };
 }
 
 /**
  * Returns the location for a given function path. If the path represents a
  * function declaration, the location will begin after the function identifier
  * but before the function parameters.
  */
@@ -2680,22 +2690,18 @@ module.exports = findLastIndex;
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getFramework = getFramework;
 
 var _getSymbols = __webpack_require__(1457);
 
-var _getSymbols2 = _interopRequireDefault(_getSymbols);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
 function getFramework(sourceId) {
-  const sourceSymbols = (0, _getSymbols2.default)(sourceId);
+  const sourceSymbols = (0, _getSymbols.getSymbols)(sourceId);
 
   if (isReactComponent(sourceSymbols)) {
     return "React";
   }
   if (isAngularComponent(sourceSymbols)) {
     return "Angular";
   }
   if (isVueComponent(sourceSymbols)) {
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-content-script-sources.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-content-script-sources.js
@@ -1,13 +1,10 @@
 "use strict";
 
-/* global ExtensionTestUtils, closeTab, openToolboxForTab, assertDebugLine,
-          waitForSelectedSource */
-
 // Tests that the content scripts are listed in the source tree.
 
 async function selectContentScriptSources(dbg) {
   await waitForSources(dbg, "content_script.js");
 
   // Select a source.
   await selectSource(dbg, "content_script.js");
 
@@ -62,18 +59,18 @@ add_task(async function() {
   await selectContentScriptSources(dbg);
 
   await addBreakpoint(dbg, "content_script.js", 2);
 
   for (let i = 1; i < 3; i++) {
     info(`Reloading tab (${i} time)`);
     gBrowser.reloadTab(gBrowser.selectedTab);
     await waitForPaused(dbg);
-    await waitForSources(dbg, "content_script.js");
     await waitForSelectedSource(dbg, "content_script.js");
+
     ok(
       findElementWithSelector(dbg, ".sources-list .focused"),
       "Source is focused"
     );
     assertPausedLocation(dbg);
     assertDebugLine(dbg, 2);
     await resume(dbg);
   }
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-highlight.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-highlight.js
@@ -8,22 +8,18 @@
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
   const { selectors: { getSource }, getState } = dbg;
   const sourceUrl = EXAMPLE_URL + "long.js";
 
   // The source itself doesn't even exist yet, and using
   // `selectSourceURL` will set a pending request to load this source
   // and highlight a specific line.
-  dbg.actions.selectSourceURL(sourceUrl, { location: { line: 66 } });
 
-  // Wait for the source text to load and make sure we're in the right
-  // place.
-  await waitForSelectedSource(dbg, sourceUrl);
-  log(`loaded source`);
+  await selectSource(dbg, sourceUrl, 66)
 
   // TODO: revisit highlighting lines when the debugger opens
   // assertHighlightLocation(dbg, "long.js", 66);
 
   log(`Select line 16 and make sure the editor scrolled.`);
   await selectSource(dbg, "long.js", 16);
   await waitForElementWithSelector(dbg, ".CodeMirror-code > .highlight-line");
   assertHighlightLocation(dbg, "long.js", 16);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-outline.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-outline.js
@@ -12,17 +12,16 @@ function getNthItem(dbg, index) {
   return findElement(dbg, "outlineItem", index);
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
   const { selectors: { getSelectedSource }, getState } = dbg;
 
   await selectSource(dbg, "simple1", 1);
-  await waitForSelectedSource(dbg, "simple1");
 
   findElementWithSelector(dbg, ".outline-tab").click();
   is(getItems(dbg).length, 5, "5 items in the list");
 
   // click on an element
   const item = getNthItem(dbg, 3);
   is(item.innerText, "evaledFunc()", "got evaled func");
   item.click();
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js
@@ -1,48 +1,45 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+async function waitForConsoleLink(dbg, text) {
+  const toolbox = dbg.toolbox;
+  const console = await toolbox.selectTool("webconsole");
+  const hud = console.hud;
+
+  return waitFor(() => {
+    // Wait until the message updates.
+    const found = hud.ui.outputNode.querySelector(".frame-link-source");
+    if (!found) {
+      return false;
+    }
+
+    const linkText = found.textContent;
+    if (!text) {
+      return linkText;
+    }
+
+    return linkText == text ? linkText : null;
+  });
+}
+
 // Tests that pretty-printing updates console messages.
-
 add_task(async function() {
   const dbg = await initDebugger("doc-minified.html");
   invokeInTab("arithmetic");
 
   info("Switch to console and check message");
-  const toolbox = dbg.toolbox;
-  const console = await toolbox.selectTool("webconsole");
-  const hud = console.hud;
-
-  let node = await waitFor(() =>
-    hud.ui.outputNode.querySelector(".frame-link-source")
-  );
-  const initialLocation = "math.min.js:3:65";
-  is(node.textContent, initialLocation, "location is correct in minified code");
+  await waitForConsoleLink(dbg,  "math.min.js:3:65");
 
   info("Switch back to debugger and pretty-print");
-  await toolbox.selectTool("jsdebugger");
+  await dbg.toolbox.selectTool("jsdebugger");
   await selectSource(dbg, "math.min.js", 2);
-  clickElement(dbg, "prettyPrintButton");
 
-  await waitForSource(dbg, "math.min.js:formatted");
-  const ppSrc = findSource(dbg, "math.min.js:formatted");
-
-  ok(ppSrc, "Pretty-printed source exists");
+  clickElement(dbg, "prettyPrintButton");
+  await waitForSelectedSource(dbg, "math.min.js:formatted");
 
   info("Switch back to console and check message");
-  node = await waitFor(() => {
-    // Wait until the message updates.
-    const found = hud.ui.outputNode.querySelector(".frame-link-source");
-    if (found.textContent == initialLocation) {
-      return null;
-    }
-    return found;
-  });
-
-  is(
-    node.textContent,
-    "math.min.js:formatted:22",
-    "location is correct in minified code"
-  );
+  await waitForConsoleLink(dbg, "math.min.js:formatted:22");
+  ok(true);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js
@@ -16,18 +16,16 @@ async function waitForBreakpoint(dbg, lo
     "Waiting for breakpoint"
   );
 }
 
 add_task(async function() {
   const dbg = await initDebugger("reload/doc-reload.html");
   await waitForSource(dbg, "sjs_code_reload");
   await selectSource(dbg, "sjs_code_reload");
-  await waitForSelectedSource(dbg, "sjs_code_reload");
-
   await addBreakpoint(dbg, "sjs_code_reload", 2);
 
   await reload(dbg, "sjs_code_reload");
 
   const source = findSource(dbg, "sjs_code_reload");
   const location = { sourceId: source.id, line: 6 };
 
   await waitForBreakpoint(dbg, location);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps2.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps2.js
@@ -40,13 +40,14 @@ add_task(async function() {
   invokeInTab("logMessage");
 
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
 
   // Tests the existence of the sourcemap link in the original source.
   ok(findElement(dbg, "sourceMapLink"), "Sourcemap link in original source");
   await selectSource(dbg, "main.min.js");
+
   ok(
     !findElement(dbg, "sourceMapLink"),
     "No Sourcemap link exists in generated source"
   );
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
@@ -21,17 +21,16 @@ add_task(async function test() {
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
-
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
 
   assertSelectedFile(dbg, "bundle.js");
   assertDebugLine(dbg, 42309);
--- a/devtools/client/debugger/new/test/mochitest/head.js
+++ b/devtools/client/debugger/new/test/mochitest/head.js
@@ -172,20 +172,21 @@ function waitForThreadEvents(dbg, eventN
 function waitForState(dbg, predicate, msg) {
   return new Promise(resolve => {
     info(`Waiting for state change: ${msg || ""}`);
     if (predicate(dbg.store.getState())) {
       return resolve();
     }
 
     const unsubscribe = dbg.store.subscribe(() => {
-      if (predicate(dbg.store.getState())) {
+      const result = predicate(dbg.store.getState())
+      if (result) {
         info(`Finished waiting for state change: ${msg || ""}`);
         unsubscribe();
-        resolve();
+        resolve(result);
       }
     });
   });
 }
 
 /**
  * Waits for sources to be loaded.
  *
@@ -225,17 +226,17 @@ function waitForSources(dbg, ...sources)
  * @param {String} source
  * @return {Promise}
  * @static
  */
 function waitForSource(dbg, url) {
   return waitForState(dbg, state => {
     const sources = dbg.selectors.getSources(state);
     return sources.find(s => (s.get("url") || "").includes(url));
-  });
+  }, `source exists`);
 }
 
 async function waitForElement(dbg, name) {
   await waitUntil(() => findElement(dbg, name));
   return findElement(dbg, name);
 }
 
 async function waitForElementWithSelector(dbg, selector) {
@@ -587,19 +588,20 @@ function waitForLoadedSources(dbg) {
  *
  * @memberof mochitest/actions
  * @param {Object} dbg
  * @param {String} url
  * @param {Number} line
  * @return {Promise}
  * @static
  */
-function selectSource(dbg, url, line) {
+async function selectSource(dbg, url, line) {
   const source = findSource(dbg, url);
-  return dbg.actions.selectLocation({ sourceId: source.id, line });
+  await dbg.actions.selectLocation({ sourceId: source.id, line });
+  return waitForSelectedSource(dbg, url);
 }
 
 function closeTab(dbg, url) {
   const source = findSource(dbg, url);
   return dbg.actions.closeTab(source.url);
 }
 
 /**
--- a/devtools/client/inspector/fonts/components/Font.js
+++ b/devtools/client/inspector/fonts/components/Font.js
@@ -5,18 +5,16 @@
 "use strict";
 
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const FontPreview = createFactory(require("./FontPreview"));
 
-loader.lazyRequireGetter(this, "clipboardHelper", "devtools/shared/platform/clipboard");
-
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 
 class Font extends PureComponent {
   static get propTypes() {
     return {
       font: PropTypes.shape(Types.font).isRequired,
       fontOptions: PropTypes.shape(Types.fontOptions).isRequired,
@@ -27,33 +25,28 @@ class Font extends PureComponent {
   constructor(props) {
     super(props);
 
     this.state = {
       isFontFaceRuleExpanded: false,
     };
 
     this.onFontFaceRuleToggle = this.onFontFaceRuleToggle.bind(this);
-    this.onCopyURL = this.onCopyURL.bind(this);
   }
 
   componentWillReceiveProps(newProps) {
     if (this.props.font.name === newProps.font.name) {
       return;
     }
 
     this.setState({
       isFontFaceRuleExpanded: false,
     });
   }
 
-  onCopyURL() {
-    clipboardHelper.copyString(this.props.font.URI);
-  }
-
   onFontFaceRuleToggle(event) {
     this.setState({
       isFontFaceRuleExpanded: !this.state.isFontFaceRuleExpanded
     });
     event.stopPropagation();
   }
 
   renderFontCSSCode(rule, ruleText) {
@@ -83,43 +76,37 @@ class Font extends PureComponent {
             className: "font-css-code-expander",
             onClick: this.onFontFaceRuleToggle,
           }
         ),
       trailing
     );
   }
 
-  renderFontOrigin(url) {
+  renderFontTypeAndURL(url, format) {
     if (!url) {
       return dom.p(
         {
-          className: "font-origin system"
+          className: "font-format-url"
         },
         getStr("fontinspector.system")
       );
     }
 
     return dom.p(
       {
-        className: "font-origin remote",
+        className: "font-format-url"
       },
-      dom.span(
+      getStr("fontinspector.remote"),
+      dom.a(
         {
-          className: "url",
-          title: url
+          className: "font-url",
+          href: url
         },
-        url
-      ),
-      dom.button(
-        {
-          className: "copy-icon",
-          onClick: this.onCopyURL,
-          title: getStr("fontinspector.copyURL"),
-        }
+        format
       )
     );
   }
 
   renderFontName(name) {
     return dom.h1(
       {
         className: "font-name"
@@ -147,28 +134,29 @@ class Font extends PureComponent {
       font,
       fontOptions,
       onPreviewFonts,
     } = this.props;
 
     let { previewText } = fontOptions;
 
     let {
+      format,
       name,
       previewUrl,
       rule,
       ruleText,
       URI,
     } = font;
 
     return dom.li(
       {
         className: "font",
       },
       this.renderFontName(name),
       FontPreview({ previewText, previewUrl, onPreviewFonts }),
-      this.renderFontOrigin(URI),
+      this.renderFontTypeAndURL(URI, format),
       this.renderFontCSSCode(rule, ruleText)
     );
   }
 }
 
 module.exports = Font;
--- a/devtools/client/inspector/fonts/test/browser.ini
+++ b/devtools/client/inspector/fonts/test/browser.ini
@@ -10,15 +10,13 @@ support-files =
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/shared-head.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_fontinspector.js]
-[browser_fontinspector_copy-URL.js]
-subsuite = clipboard
 [browser_fontinspector_edit-previews.js]
 [browser_fontinspector_expand-css-code.js]
 [browser_fontinspector_other-fonts.js]
 [browser_fontinspector_text-node.js]
 [browser_fontinspector_theme-change.js]
--- a/devtools/client/inspector/fonts/test/browser_fontinspector.js
+++ b/devtools/client/inspector/fonts/test/browser_fontinspector.js
@@ -5,59 +5,73 @@
 
 requestLongerTimeout(2);
 
 const TEST_URI = URL_ROOT + "browser_fontinspector.html";
 const FONTS = [{
   name: "Ostrich Sans Medium",
   remote: true,
   url: URL_ROOT + "ostrich-regular.ttf",
+  format: "truetype",
   cssName: "bar"
 }, {
   name: "Ostrich Sans Black",
   remote: true,
   url: URL_ROOT + "ostrich-black.ttf",
+  format: "",
   cssName: "bar"
 }, {
   name: "Ostrich Sans Black",
   remote: true,
   url: URL_ROOT + "ostrich-black.ttf",
+  format: "",
   cssName: "bar"
 }, {
   name: "Ostrich Sans Medium",
   remote: true,
   url: URL_ROOT + "ostrich-regular.ttf",
+  format: "",
   cssName: "barnormal"
 }];
 
 add_task(function* () {
   let { inspector, view } = yield openFontInspectorForURL(TEST_URI);
   ok(!!view, "Font inspector document is alive.");
 
   let viewDoc = view.document;
 
   yield testBodyFonts(inspector, viewDoc);
   yield testDivFonts(inspector, viewDoc);
 });
 
 function isRemote(fontLi) {
-  return fontLi.querySelector(".font-origin").classList.contains("remote");
+  return fontLi.querySelectorAll(".font-format-url a").length === 1;
+}
+
+function getFormat(fontLi) {
+  let link = fontLi.querySelector(".font-format-url a");
+  if (!link) {
+    return null;
+  }
+
+  return link.textContent;
 }
 
 function* testBodyFonts(inspector, viewDoc) {
   let lis = getUsedFontsEls(viewDoc);
   is(lis.length, 5, "Found 5 fonts");
 
   for (let i = 0; i < FONTS.length; i++) {
     let li = lis[i];
     let font = FONTS[i];
 
-    is(getName(li), font.name, `font ${i} right font name`);
-    is(isRemote(li), font.remote, `font ${i} remote value correct`);
-    is(li.querySelector(".font-origin").textContent, font.url, `font ${i} url correct`);
+    is(getName(li), font.name, "font " + i + " right font name");
+    is(isRemote(li), font.remote, "font " + i + " remote value correct");
+    is(li.querySelector(".font-url").href, font.url, "font " + i + " url correct");
+    is(getFormat(li), font.format, "font " + i + " format correct");
   }
 
   // test that the bold and regular fonts have different previews
   let regSrc = lis[0].querySelector(".font-preview").src;
   let boldSrc = lis[1].querySelector(".font-preview").src;
   isnot(regSrc, boldSrc, "preview for bold font is different from regular");
 
   // test system font
deleted file mode 100644
--- a/devtools/client/inspector/fonts/test/browser_fontinspector_copy-URL.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that an icon appears next to web font URLs, and that clicking it copies the URL
-// to the clipboard thanks to it.
-
-const TEST_URI = URL_ROOT + "browser_fontinspector.html";
-
-add_task(async function() {
-  let { view } = await openFontInspectorForURL(TEST_URI);
-  let viewDoc = view.document;
-
-  let fontEl = getUsedFontsEls(viewDoc)[0];
-  let linkEl = fontEl.querySelector(".font-origin");
-  let iconEl = linkEl.querySelector(".copy-icon");
-
-  ok(iconEl, "The icon is displayed");
-  is(iconEl.getAttribute("title"), "Copy URL", "This is the right icon");
-
-  info("Clicking the button and waiting for the clipboard to receive the URL");
-  await waitForClipboardPromise(() => iconEl.click(), linkEl.textContent);
-});
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -118,17 +118,16 @@ devtools.jar:
     skin/images/breadcrumbs-divider.svg (themes/images/breadcrumbs-divider.svg)
     skin/images/filters.svg (themes/images/filters.svg)
     skin/images/filter-swatch.svg (themes/images/filter-swatch.svg)
     skin/images/grid.svg (themes/images/grid.svg)
     skin/images/angle-swatch.svg (themes/images/angle-swatch.svg)
     skin/images/pseudo-class.svg (themes/images/pseudo-class.svg)
     skin/images/controls.png (themes/images/controls.png)
     skin/images/controls@2x.png (themes/images/controls@2x.png)
-    skin/images/copy.svg (themes/images/copy.svg)
     skin/images/animation-fast-track.svg (themes/images/animation-fast-track.svg)
     skin/images/performance-details-waterfall.svg (themes/images/performance-details-waterfall.svg)
     skin/images/performance-details-call-tree.svg (themes/images/performance-details-call-tree.svg)
     skin/images/performance-details-flamegraph.svg (themes/images/performance-details-flamegraph.svg)
     skin/breadcrumbs.css (themes/breadcrumbs.css)
     skin/chart.css (themes/chart.css)
     skin/widgets.css (themes/widgets.css)
     skin/images/power.svg (themes/images/power.svg)
--- a/devtools/client/locales/en-US/font-inspector.properties
+++ b/devtools/client/locales/en-US/font-inspector.properties
@@ -4,25 +4,24 @@
 
 # LOCALIZATION NOTE This file contains the Font Inspector strings.
 # The Font Inspector is a panel accessible in the Inspector sidebar.
 
 # LOCALIZATION NOTE (fontinspector.system) This label indicates that the font is a local
 # system font.
 fontinspector.system=system
 
+# LOCALIZATION NOTE (fontinspector.remote) This label indicates that the font is a remote
+# font.
+fontinspector.remote=remote
+
 # LOCALIZATION NOTE (fontinspector.noFontsOnSelectedElement): This label is shown when
 # no fonts found on the selected element.
 fontinspector.noFontsOnSelectedElement=No fonts were found for the current element.
 
 # LOCALIZATION NOTE (fontinspector.otherFontsInPageHeader): This is the text for the
 # header of a collapsible section containing other fonts used in the page.
 fontinspector.otherFontsInPageHeader=Other fonts in page
 
 # LOCALIZATION NOTE (fontinspector.editPreview): This is the text that appears in a
 # tooltip on hover of a font preview string. Clicking on the string opens a text input
 # where users can type to change the preview text.
 fontinspector.editPreview=Click to edit preview
-
-# LOCALIZATION NOTE (fontinspector.copyURL): This is the text that appears in a tooltip
-# displayed when the user hovers over the copy icon next to the font URL.
-# Clicking the copy icon copies the full font URL to the user's clipboard
-fontinspector.copyURL=Copy URL
--- a/devtools/client/themes/fonts.css
+++ b/devtools/client/themes/fonts.css
@@ -21,17 +21,16 @@
   list-style: none;
 }
 
 .font {
   border: 1px solid var(--theme-splitter-color);
   border-width: 0 1px 1px 0;
   display: grid;
   grid-template-columns: 1fr auto;
-  grid-column-gap: 10px;
   padding: 10px 20px;
 }
 
 #font-container .theme-twisty {
   display: inline-block;
   cursor: pointer;
   vertical-align: bottom;
 }
@@ -104,49 +103,40 @@
   color: var(--theme-body-color-inactive);
   border-radius: 3px;
   border-style: solid;
   border-width: 1px;
   text-align: center;
   vertical-align: middle;
 }
 
-.font-origin {
+.font-format-url {
+  text-transform: capitalize;
   margin-top: .2em;
   color: var(--grey-50);
-  justify-self: start;
-}
-
-.font-origin.system {
-  text-transform: capitalize;
-}
-
-.font-origin.remote {
-  display: grid;
-  grid-template-columns: 1fr 20px;
 }
 
-.font-origin.remote .url {
-  text-overflow: ellipsis;
-  overflow: hidden;
-  white-space: nowrap;
+.font-url {
+  margin-inline-start: .5em;
+  text-decoration: underline;
+  color: var(--theme-highlight-blue);
+  background: transparent;
+  border: none;
+  cursor: pointer;
 }
 
-.font-origin .copy-icon {
-  border: 0;
-  padding: 0;
-  position: relative;
-  cursor: pointer;
-  width: 12px;
-  height: 12px;
-  place-self: center;
-
-  background: url(chrome://devtools/skin/images/copy.svg) no-repeat;
-  background-size: 12px;
-  background-position-x: -1px;
+.font-url::after {
+  content: "";
+  display: inline-block;
+  height: 13px;
+  width: 13px;
+  margin: -.3rem .15rem 0 0.25rem;
+  vertical-align: middle;
+  background-image: url(chrome://devtools-shim/content/aboutdevtools/images/external-link.svg);
+  background-repeat: no-repeat;
+  background-size: 13px 13px;
   -moz-context-properties: fill;
-  fill: var(--theme-toolbar-color);
-
+  fill: var(--blue-60);
 }
 
 #font-container .devtools-sidepanel-no-result + .accordion {
   border-block-start: 1px solid var(--theme-splitter-color);
 }
deleted file mode 100644
--- a/devtools/client/themes/images/copy.svg
+++ /dev/null
@@ -1,6 +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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" fill="context-fill #0b0b0b">
-  <path d="M5.70001221,11.125 L5.70001221,4.625 L7.66001225,4.625 L7.66001225,6.94642857 C7.66001225,7.20271429 7.87953225,7.41071429 8.15001225,7.41071429 L10.6000123,7.41071429 L10.6000123,11.125 L5.70001221,11.125 Z M4.7,5.475 L4.7,7.275 L2,7.275 L2,0.975 L3.8,0.975 L3.8,3.225 C3.8,3.4734 4.0016,3.675 4.25,3.675 L6.5,3.675 C5.5064,3.675 4.7,4.4814 4.7,5.475 Z M6.84002447,3.00050006 L4.65002441,3.00050006 L4.65002441,0.8105 L6.84002447,3.00050006 Z M10.5,6.6000061 L8.5,6.6000061 L8.5,4.6000061 L10.5,6.6000061 Z M11.28025,6.21975 L9.03025,3.96975 C8.89,3.82875 8.6995,3.75 8.5,3.75 L7.75,3.75 L7.75,3 C7.75,2.80125 7.67125,2.61 7.53025,2.46975 L5.28025,0.21975 C5.14,0.07875 4.94875,0 4.75,0 L2.5,0 C1.672,0 1,0.672 1,1.5 L1,6.75 C1,7.578 1.672,8.25 2.5,8.25 L4.75,8.25 L4.75,10.5 C4.75,11.328 5.422,12 6.25,12 L10,12 C10.828,12 11.5,11.328 11.5,10.5 L11.5,6.75 C11.5,6.55125 11.42125,6.36 11.28025,6.21975 Z"></path>
-</svg>
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1537,23 +1537,16 @@ FragmentOrElement::MarkNodeChildren(nsIN
   if (o) {
     JS::ExposeObjectToActiveJS(o);
   }
 
   EventListenerManager* elm = aNode->GetExistingListenerManager();
   if (elm) {
     elm->MarkForCC();
   }
-
-  if (aNode->HasProperties()) {
-    nsIDocument* ownerDoc = aNode->OwnerDoc();
-    ownerDoc->PropertyTable(DOM_USER_DATA)->
-      Enumerate(aNode, FragmentOrElement::MarkUserData,
-                &nsCCUncollectableMarker::sGeneration);
-  }
 }
 
 nsINode*
 FindOptimizableSubtreeRoot(nsINode* aNode)
 {
   nsINode* p;
   while ((p = aNode->GetParentNode())) {
     if (aNode->UnoptimizableCCNode()) {
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -81,25 +81,16 @@ nsCCUncollectableMarker::Init()
   NS_ENSURE_SUCCESS(rv, rv);
 
   sInited = true;
 
   return NS_OK;
 }
 
 static void
-MarkUserData(void* aNode, nsAtom* aKey, void* aValue, void* aData)
-{
-  nsIDocument* d = static_cast<nsINode*>(aNode)->GetUncomposedDoc();
-  if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
-    Element::MarkUserData(aNode, aKey, aValue, aData);
-  }
-}
-
-static void
 MarkChildMessageManagers(nsIMessageBroadcaster* aMM)
 {
   aMM->MarkForCC();
 
   uint32_t tabChildCount = 0;
   aMM->GetChildCount(&tabChildCount);
   for (uint32_t j = 0; j < tabChildCount; ++j) {
     nsCOMPtr<nsIMessageListenerManager> childMM;
@@ -185,18 +176,17 @@ MarkMessageManagers()
     }
   }
   if (nsFrameMessageManager::sSameProcessParentManager) {
     nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
   }
 }
 
 void
-MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
-                  bool aPrepareForCC)
+MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS)
 {
   if (!aViewer) {
     return;
   }
 
   nsIDocument *doc = aViewer->GetDocument();
   if (doc &&
       doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
@@ -210,111 +200,104 @@ MarkContentViewer(nsIContentViewer* aVie
       if (win) {
         elm = win->GetExistingListenerManager();
         if (elm) {
           elm->MarkForCC();
         }
         static_cast<nsGlobalWindowInner*>(win.get())->AsInner()->
           TimeoutManager().UnmarkGrayTimers();
       }
-    } else if (aPrepareForCC) {
-      // Unfortunately we need to still mark user data just before running CC so
-      // that it has the right generation.
-      doc->PropertyTable(DOM_USER_DATA)->
-        EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
     }
   }
   if (doc) {
     if (nsPIDOMWindowInner* inner = doc->GetInnerWindow()) {
       inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     }
     if (nsPIDOMWindowOuter* outer = doc->GetWindow()) {
       outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     }
   }
 }
 
-void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS,
-                  bool aPrepareForCC);
+void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS);
 
 void
-MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS, bool aPrepareForCC)
+MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS)
 {
   if (!aSHEntry) {
     return;
   }
 
   nsCOMPtr<nsIContentViewer> cview;
   aSHEntry->GetContentViewer(getter_AddRefs(cview));
-  MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
+  MarkContentViewer(cview, aCleanupJS);
 
   nsCOMPtr<nsIDocShellTreeItem> child;
   int32_t i = 0;
   while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
          child) {
-    MarkDocShell(child, aCleanupJS, aPrepareForCC);
+    MarkDocShell(child, aCleanupJS);
   }
 
   nsCOMPtr<nsISHContainer> shCont = do_QueryInterface(aSHEntry);
   int32_t count;
   shCont->GetChildCount(&count);
   for (i = 0; i < count; ++i) {
     nsCOMPtr<nsISHEntry> childEntry;
     shCont->GetChildAt(i, getter_AddRefs(childEntry));
-    MarkSHEntry(childEntry, aCleanupJS, aPrepareForCC);
+    MarkSHEntry(childEntry, aCleanupJS);
   }
 
 }
 
 void
-MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS, bool aPrepareForCC)
+MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS)
 {
   nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
   if (!shell) {
     return;
   }
 
   nsCOMPtr<nsIContentViewer> cview;
   shell->GetContentViewer(getter_AddRefs(cview));
-  MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
+  MarkContentViewer(cview, aCleanupJS);
 
   nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
   nsCOMPtr<nsISHistory> history;
   webNav->GetSessionHistory(getter_AddRefs(history));
   if (history) {
     int32_t i, historyCount;
     history->GetCount(&historyCount);
     for (i = 0; i < historyCount; ++i) {
       nsCOMPtr<nsISHEntry> shEntry;
       history->GetEntryAtIndex(i, false, getter_AddRefs(shEntry));
 
-      MarkSHEntry(shEntry, aCleanupJS, aPrepareForCC);
+      MarkSHEntry(shEntry, aCleanupJS);
     }
   }
 
   int32_t i, childCount;
   aNode->GetChildCount(&childCount);
   for (i = 0; i < childCount; ++i) {
     nsCOMPtr<nsIDocShellTreeItem> child;
     aNode->GetChildAt(i, getter_AddRefs(child));
-    MarkDocShell(child, aCleanupJS, aPrepareForCC);
+    MarkDocShell(child, aCleanupJS);
   }
 }
 
 void
-MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS,
-               bool aPrepareForCC)
+MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS)
 {
   nsCOMPtr<nsISupports> iter;
   while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
          iter) {
     if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(iter)) {
       nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
 
-      MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC);
+      MarkDocShell(rootDocShell, aCleanupJS);
 
       nsCOMPtr<nsITabChild> tabChild =
         rootDocShell ? rootDocShell->GetTabChild() : nullptr;
       if (tabChild) {
         nsCOMPtr<nsIContentFrameMessageManager> mm;
         tabChild->GetMessageManager(getter_AddRefs(mm));
         if (mm) {
           // MarkForCC ends up calling UnmarkGray on message listeners, which
@@ -347,21 +330,21 @@ nsCCUncollectableMarker::Observe(nsISupp
 
     return NS_OK;
   }
 
   NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
                !strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
 
   // JS cleanup can be slow. Do it only if there has been a GC.
-  bool cleanupJS =
+  const bool cleanupJS =
     nsJSContext::CleanupsSinceLastGC() == 0 &&
     !strcmp(aTopic, "cycle-collector-forget-skippable");
 
-  bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
+  const bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
   if (prepareForCC) {
     Element::ClearContentUnbinder();
   }
 
   // Increase generation to effectively unmark all current objects
   if (!++sGeneration) {
     ++sGeneration;
   }
@@ -373,46 +356,46 @@ nsCCUncollectableMarker::Observe(nsISupp
   // Iterate all toplevel windows
   nsCOMPtr<nsISimpleEnumerator> windowList;
   nsCOMPtr<nsIWindowMediator> med =
     do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
   if (med) {
     rv = med->GetEnumerator(nullptr, getter_AddRefs(windowList));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    MarkWindowList(windowList, cleanupJS, prepareForCC);
+    MarkWindowList(windowList, cleanupJS);
   }
 
   nsCOMPtr<nsIWindowWatcher> ww =
     do_GetService(NS_WINDOWWATCHER_CONTRACTID);
   if (ww) {
     rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    MarkWindowList(windowList, cleanupJS, prepareForCC);
+    MarkWindowList(windowList, cleanupJS);
   }
 
   nsCOMPtr<nsIAppShellService> appShell =
     do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
   if (appShell) {
     nsCOMPtr<nsIXULWindow> hw;
     appShell->GetHiddenWindow(getter_AddRefs(hw));
     if (hw) {
       nsCOMPtr<nsIDocShell> shell;
       hw->GetDocShell(getter_AddRefs(shell));
-      MarkDocShell(shell, cleanupJS, prepareForCC);
+      MarkDocShell(shell, cleanupJS);
     }
     bool hasHiddenPrivateWindow = false;
     appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
     if (hasHiddenPrivateWindow) {
       appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
       if (hw) {
         nsCOMPtr<nsIDocShell> shell;
         hw->GetDocShell(getter_AddRefs(shell));
-        MarkDocShell(shell, cleanupJS, prepareForCC);
+        MarkDocShell(shell, cleanupJS);
       }
     }
   }
 
 #ifdef MOZ_XUL
   nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
   if (xulCache) {
     xulCache->MarkInCCGeneration(sGeneration);
--- a/dom/base/nsDeprecatedOperationList.h
+++ b/dom/base/nsDeprecatedOperationList.h
@@ -12,17 +12,16 @@
 
 DEPRECATED_OPERATION(EnablePrivilege)
 DEPRECATED_OPERATION(DOMExceptionCode)
 DEPRECATED_OPERATION(MutationEvent)
 DEPRECATED_OPERATION(Components)
 DEPRECATED_OPERATION(PrefixedVisibilityAPI)
 DEPRECATED_OPERATION(NodeIteratorDetach)
 DEPRECATED_OPERATION(LenientThis)
-DEPRECATED_OPERATION(GetSetUserData)
 DEPRECATED_OPERATION(MozGetAsFile)
 DEPRECATED_OPERATION(UseOfCaptureEvents)
 DEPRECATED_OPERATION(UseOfReleaseEvents)
 DEPRECATED_OPERATION(UseOfDOM3LoadMethod)
 DEPRECATED_OPERATION(ChromeUseOfDOM3LoadMethod)
 DEPRECATED_OPERATION(ShowModalDialog)
 DEPRECATED_OPERATION(SyncXMLHttpRequest)
 DEPRECATED_OPERATION(Window_Cc_ontrollers)
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1505,18 +1505,25 @@ nsIDocument::nsIDocument()
     mValidHeight(false),
     mAutoSize(false),
     mAllowZoom(false),
     mAllowDoubleTapZoom(false),
     mValidScaleFloat(false),
     mValidMaxScale(false),
     mScaleStrEmpty(false),
     mWidthStrEmpty(false),
+    mParserAborted(false),
+    mReportedUseCounters(false),
+#ifdef DEBUG
+    mWillReparent(false),
+#endif
     mPendingFullscreenRequests(0),
     mXMLDeclarationBits(0),
+    mOnloadBlockCount(0),
+    mAsyncOnloadBlockCount(0),
     mCompatMode(eCompatibility_FullStandards),
     mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
     mStyleBackendType(StyleBackendType::None),
 #ifdef MOZILLA_INTERNAL_API
     mVisibilityState(dom::VisibilityState::Hidden),
 #else
     mDummy(0),
 #endif
@@ -1560,40 +1567,33 @@ nsIDocument::nsIDocument()
   SetIsInDocument();
   for (auto& cnt : mIncCounters) {
     cnt = 0;
   }
 }
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
-  , mParserAborted(false)
-  , mReportedUseCounters(false)
-  , mOnloadBlockCount(0)
-  , mAsyncOnloadBlockCount(0)
-#ifdef DEBUG
-  , mWillReparent(false)
-#endif
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
 
   // Start out mLastStyleSheetSet as null, per spec
   SetDOMStringToNull(mLastStyleSheetSet);
 
   // void state used to differentiate an empty source from an unselected source
   mPreloadPictureFoundSource.SetIsVoid(true);
   // For determining if this is a flash document which should be
   // blocked based on its principal.
   mPrincipalFlashClassifier = new PrincipalFlashClassifier();
 }
 
 void
-nsDocument::ClearAllBoxObjects()
+nsIDocument::ClearAllBoxObjects()
 {
   if (mBoxObjectTable) {
     for (auto iter = mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
       nsPIBoxObject* boxObject = iter.UserData();
       if (boxObject) {
         boxObject->Clear();
       }
     }
@@ -2202,54 +2202,40 @@ nsDocument::Init()
   mozilla::HoldJSObjects(this);
 
   return NS_OK;
 }
 
 void
 nsIDocument::DeleteAllProperties()
 {
-  for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) {
-    PropertyTable(i)->DeleteAllProperties();
-  }
+  PropertyTable().DeleteAllProperties();
 }
 
 void
 nsIDocument::DeleteAllPropertiesFor(nsINode* aNode)
 {
-  for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) {
-    PropertyTable(i)->DeleteAllPropertiesFor(aNode);
-  }
-}
-
-nsPropertyTable*
-nsIDocument::GetExtraPropertyTable(uint16_t aCategory)
-{
-  NS_ASSERTION(aCategory > 0, "Category 0 should have already been handled");
-  while (aCategory >= mExtraPropertyTables.Length() + 1) {
-    mExtraPropertyTables.AppendElement(new nsPropertyTable());
-  }
-  return mExtraPropertyTables[aCategory - 1];
+  PropertyTable().DeleteAllPropertiesFor(aNode);
 }
 
 bool
 nsIDocument::IsVisibleConsideringAncestors() const
 {
   const nsIDocument *parent = this;
   do {
     if (!parent->IsVisible()) {
       return false;
     }
   } while ((parent = parent->GetParentDocument()));
 
   return true;
       }
 
 void
-nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
+nsIDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
 {
   nsCOMPtr<nsIURI> uri;
   nsCOMPtr<nsIPrincipal> principal;
   if (aChannel) {
     // Note: this code is duplicated in XULDocument::StartDocumentLoad and
     // nsScriptSecurityManager::GetChannelResultPrincipal.
     // Note: this should match nsDocShell::OnLoadingSite
     NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
@@ -2292,18 +2278,19 @@ nsDocument::Reset(nsIChannel* aChannel, 
       mChromeXHRDocBaseURI = nullptr;
     }
   }
 
   mChannel = aChannel;
 }
 
 void
-nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
-                       nsIPrincipal* aPrincipal)
+nsIDocument::ResetToURI(nsIURI* aURI,
+                        nsILoadGroup* aLoadGroup,
+                        nsIPrincipal* aPrincipal)
 {
   NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
           ("DOCUMENT %p ResetToURI %s", this, aURI->GetSpecOrDefault().get()));
 
   mSecurityInfo = nullptr;
 
@@ -2442,17 +2429,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
 
   // Refresh the principal on the compartment.
   if (nsPIDOMWindowInner* win = GetInnerWindow()) {
     nsGlobalWindowInner::Cast(win)->RefreshCompartmentPrincipal();
   }
 }
 
 already_AddRefed<nsIPrincipal>
-nsDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
+nsIDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
 {
   if (!aPrincipal) {
     return nullptr;
   }
 
   // We can't load a document with an expanded principal. If we're given one,
   // automatically downgrade it to the last principal it subsumes (which is the
   // extension principal, in the case of extension content scripts).
@@ -2681,17 +2668,17 @@ WarnIfSandboxIneffective(nsIDocShell* aD
                                     parentDocument,
                                     nsContentUtils::eSECURITY_PROPERTIES,
                                     "BothAllowScriptsAndSameOriginPresent",
                                     nullptr, 0, iframeUri);
   }
 }
 
 bool
-nsDocument::IsSynthesized() {
+nsIDocument::IsSynthesized() {
   nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(mChannel);
   bool synthesized = false;
   if (internalChan) {
     DebugOnly<nsresult> rv = internalChan->GetResponseSynthesized(&synthesized);
     MOZ_ASSERT(NS_SUCCEEDED(rv), "GetResponseSynthesized shouldn't fail.");
   }
   return synthesized;
 }
@@ -2859,17 +2846,17 @@ nsDocument::StartDocumentLoad(const char
   // in an early stage to reduce the blocking time.
   mFlashClassification = FlashClassification::Unclassified;
   mPrincipalFlashClassifier->AsyncClassify(GetPrincipal());
 
   return NS_OK;
 }
 
 void
-nsDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
+nsIDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
 {
   for (uint32_t i = 0; i < aMessages.Length(); ++i) {
     nsAutoString messageTag;
     aMessages[i]->GetTag(messageTag);
 
     nsAutoString category;
     aMessages[i]->GetCategory(category);
 
@@ -2935,17 +2922,17 @@ nsIDocument::ApplySettingsFromCSP(bool a
     if (!mUpgradeInsecurePreloads) {
       rv = preloadCsp->GetUpgradeInsecureRequests(&mUpgradeInsecurePreloads);
       NS_ENSURE_SUCCESS_VOID(rv);
     }
   }
 }
 
 nsresult
-nsDocument::InitCSP(nsIChannel* aChannel)
+nsIDocument::InitCSP(nsIChannel* aChannel)
 {
   MOZ_ASSERT(!mScriptGlobalObject,
              "CSP must be initialized before mScriptGlobalObject is set!");
   if (!CSPService::sCSPEnabled) {
     MOZ_LOG(gCspPRLog, LogLevel::Debug,
            ("CSP is disabled, skipping CSP init for document %p", this));
     return NS_OK;
   }
@@ -3003,17 +2990,17 @@ nsDocument::InitCSP(nsIChannel* aChannel
     }
 
     return NS_OK;
   }
 
   MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Document is an add-on or CSP header specified %p", this));
 
   nsCOMPtr<nsIContentSecurityPolicy> csp;
-  rv = principal->EnsureCSP(this, getter_AddRefs(csp));
+  rv = principal->EnsureCSP(static_cast<nsDocument*>(this), getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // ----- if the doc is an addon, apply its CSP.
   if (addonPolicy) {
     nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
 
     nsAutoString addonCSP;
     Unused << ExtensionPolicyService::GetSingleton().GetBaseCSP(addonCSP);
@@ -3357,17 +3344,17 @@ nsDocument::SetApplicationCache(nsIAppli
 
 void
 nsIDocument::GetContentType(nsAString& aContentType)
 {
   CopyUTF8toUTF16(GetContentTypeInternal(), aContentType);
 }
 
 void
-nsDocument::SetContentType(const nsAString& aContentType)
+nsIDocument::SetContentType(const nsAString& aContentType)
 {
   SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType));
 }
 
 bool
 nsIDocument::GetAllowPlugins()
 {
   // First, we ask our docshell if it allows plugins.
@@ -3740,17 +3727,17 @@ nsIDocument::DefaultStyleAttrURLData()
   return mCachedURLData;
 #else
   MOZ_CRASH("Should not be called for non-stylo build");
   return nullptr;
 #endif
 }
 
 void
-nsDocument::SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding)
+nsIDocument::SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding)
 {
   if (mCharacterSet != aEncoding) {
     mCharacterSet = aEncoding;
 
     if (nsPresContext* context = GetPresContext()) {
       context->DispatchCharSetChange(aEncoding);
     }
   }
@@ -4068,16 +4055,31 @@ nsIDocument::DeleteShell()
   mStyleSetFilled = false;
 
   if (IsStyledByServo()) {
     ClearStaleServoData();
     AssertNoStaleServoDataIn(static_cast<nsINode&>(*this));
   }
 }
 
+void
+nsIDocument::SetBFCacheEntry(nsIBFCacheEntry* aEntry)
+{
+  MOZ_ASSERT(IsBFCachingAllowed() || !aEntry, "You should have checked!");
+
+  if (mPresShell) {
+    if (aEntry) {
+      mPresShell->StopObservingRefreshDriver();
+    } else if (mBFCacheEntry) {
+      mPresShell->StartObservingRefreshDriver();
+    }
+  }
+  mBFCacheEntry = aEntry;
+}
+
 static void
 SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 {
   SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
 
   NS_RELEASE(e->mKey);
   if (e->mSubDocument) {
     e->mSubDocument->SetParentDocument(nullptr);
@@ -4851,17 +4853,17 @@ nsIDocument::SetContainer(nsDocShell* aC
 
 nsISupports*
 nsIDocument::GetContainer() const
 {
   return static_cast<nsIDocShell*>(mDocumentContainer);
 }
 
 void
-nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
+nsIDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
 {
   MOZ_ASSERT(aScriptGlobalObject || !mAnimationController ||
              mAnimationController->IsPausedByType(
                nsSMILTimeContainer::PAUSE_PAGEHIDE |
                nsSMILTimeContainer::PAUSE_BEGIN),
              "Clearing window pointer while animations are unpaused");
 
   if (mScriptGlobalObject && !aScriptGlobalObject) {
@@ -5103,17 +5105,17 @@ nsIDocument::RemoveObserver(nsIDocumentO
     RemoveMutationObserver(aObserver);
     return mObservers.RemoveElement(aObserver);
   }
 
   return mObservers.Contains(aObserver);
 }
 
 void
-nsDocument::MaybeEndOutermostXBLUpdate()
+nsIDocument::MaybeEndOutermostXBLUpdate()
 {
   // Only call BindingManager()->EndOutermostUpdate() when
   // we're not in an update and it is safe to run scripts.
   if (mUpdateNestLevel == 0 && mInXBLUpdate) {
     if (nsContentUtils::IsSafeToRunScript()) {
       mInXBLUpdate = false;
       BindingManager()->EndOutermostUpdate();
     } else if (!mInDestructor) {
@@ -5945,24 +5947,18 @@ nsIDocument::ResolveScheduledSVGPresAttr
 {
   for (auto iter = mLazySVGPresElements.Iter(); !iter.Done(); iter.Next()) {
     nsSVGElement* svg = iter.Get()->GetKey();
     svg->UpdateContentDeclarationBlock(StyleBackendType::Servo);
   }
   mLazySVGPresElements.Clear();
 }
 
-long
-nsDocument::BlockedTrackingNodeCount() const
-{
-  return mBlockedTrackingNodes.Length();
-}
-
 already_AddRefed<nsSimpleContentList>
-nsDocument::BlockedTrackingNodes() const
+nsIDocument::BlockedTrackingNodes() const
 {
   RefPtr<nsSimpleContentList> list = new nsSimpleContentList(nullptr);
 
   nsTArray<nsWeakPtr> blockedTrackingNodes;
   blockedTrackingNodes = mBlockedTrackingNodes;
 
   for (unsigned long i = 0; i < blockedTrackingNodes.Length(); i++) {
     nsWeakPtr weakNode = blockedTrackingNodes[i];
@@ -7288,38 +7284,30 @@ nsIDocument::AdoptNode(nsINode& aAdopted
   nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager,
                      newScope, nodesWithProperties, rv);
   if (rv.Failed()) {
     // Disconnect all nodes from their parents, since some have the old document
     // as their ownerDocument and some have this as their ownerDocument.
     nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
 
     if (!sameDocument && oldDocument) {
-      uint32_t count = nodesWithProperties.Count();
-      for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
-        for (uint32_t i = 0; i < count; ++i) {
-          // Remove all properties.
-          oldDocument->PropertyTable(j)->
-            DeleteAllPropertiesFor(nodesWithProperties[i]);
-        }
+      for (nsINode* node : nodesWithProperties) {
+        // Remove all properties.
+        oldDocument->PropertyTable().DeleteAllPropertiesFor(node);
       }
     }
 
     return nullptr;
   }
 
-  uint32_t count = nodesWithProperties.Count();
   if (!sameDocument && oldDocument) {
-    for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
-      nsPropertyTable *oldTable = oldDocument->PropertyTable(j);
-      nsPropertyTable *newTable = PropertyTable(j);
-      for (uint32_t i = 0; i < count; ++i) {
-        rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i],
-                                                        newTable);
-      }
+    nsPropertyTable& oldTable = oldDocument->PropertyTable();
+    nsPropertyTable& newTable = PropertyTable();
+    for (nsINode* node : nodesWithProperties) {
+      rv = oldTable.TransferOrDeleteAllPropertiesFor(node, newTable);
     }
 
     if (rv.Failed()) {
       // Disconnect all nodes from their parents.
       nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
 
       return nullptr;
     }
@@ -8032,18 +8020,18 @@ nsDocument::RetrieveRelevantHeaders(nsIC
 
   mLastModified.Truncate();
   if (modDate != 0) {
     GetFormattedTimeString(modDate, mLastModified);
   }
 }
 
 already_AddRefed<Element>
-nsDocument::CreateElem(const nsAString& aName, nsAtom *aPrefix,
-                       int32_t aNamespaceID, const nsAString* aIs)
+nsIDocument::CreateElem(const nsAString& aName, nsAtom *aPrefix,
+                        int32_t aNamespaceID, const nsAString* aIs)
 {
 #ifdef DEBUG
   nsAutoString qName;
   if (aPrefix) {
     aPrefix->ToString(qName);
     qName.Append(':');
   }
   qName.Append(aName);
@@ -8358,17 +8346,17 @@ nsIDocument::GetLayoutHistoryState() con
       docShell->GetLayoutHistoryState(getter_AddRefs(state));
     }
   }
 
   return state.forget();
 }
 
 void
-nsDocument::EnsureOnloadBlocker()
+nsIDocument::EnsureOnloadBlocker()
 {
   // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
   // -- it's not ours.
   if (mOnloadBlockCount != 0 && mScriptGlobalObject) {
     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
     if (loadGroup) {
       // Check first to see if mOnloadBlocker is in the loadgroup.
       nsCOMPtr<nsISimpleEnumerator> requests;
@@ -8468,46 +8456,46 @@ nsDocument::UnblockOnload(bool aFireSync
                                  false);
       asyncDispatcher->PostDOMEvent();
     }
   }
 }
 
 class nsUnblockOnloadEvent : public Runnable {
 public:
-  explicit nsUnblockOnloadEvent(nsDocument* aDoc)
+  explicit nsUnblockOnloadEvent(nsIDocument* aDoc)
     : mozilla::Runnable("nsUnblockOnloadEvent")
     , mDoc(aDoc)
   {
   }
   NS_IMETHOD Run() override {
     mDoc->DoUnblockOnload();
     return NS_OK;
   }
 private:
-  RefPtr<nsDocument> mDoc;
+  RefPtr<nsIDocument> mDoc;
 };
 
 void
-nsDocument::PostUnblockOnloadEvent()
+nsIDocument::PostUnblockOnloadEvent()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   nsCOMPtr<nsIRunnable> evt = new nsUnblockOnloadEvent(this);
   nsresult rv =
     Dispatch(TaskCategory::Other, evt.forget());
   if (NS_SUCCEEDED(rv)) {
     // Stabilize block count so we don't post more events while this one is up
     ++mOnloadBlockCount;
   } else {
     NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
   }
 }
 
 void
-nsDocument::DoUnblockOnload()
+nsIDocument::DoUnblockOnload()
 {
   NS_PRECONDITION(!mDisplayDocument,
                   "Shouldn't get here for resource document");
   NS_PRECONDITION(mOnloadBlockCount != 0,
                   "Shouldn't have a count of zero here, since we stabilized in "
                   "PostUnblockOnloadEvent");
 
   --mOnloadBlockCount;
@@ -9940,17 +9928,17 @@ nsIDocument::WarnOnceAbout(DeprecatedOpe
   MOZ_ASSERT(NS_IsMainThread());
   if (HasWarnedAbout(aOperation)) {
     return;
   }
   mDeprecationWarnedAbout[aOperation] = true;
   // Don't count deprecated operations for about pages since those pages
   // are almost in our control, and we always need to remove uses there
   // before we remove the operation itself anyway.
-  if (!static_cast<const nsDocument*>(this)->IsAboutPage()) {
+  if (!IsAboutPage()) {
     const_cast<nsIDocument*>(this)->
       SetDocumentAndPageUseCounter(OperationToUseCounter(aOperation));
   }
   uint32_t flags = asError ? nsIScriptError::errorFlag
                            : nsIScriptError::warningFlag;
   nsContentUtils::ReportToConsole(flags,
                                   NS_LITERAL_CSTRING("DOM Core"), this,
                                   nsContentUtils::eDOM_PROPERTIES,
@@ -11775,50 +11763,43 @@ nsIDocument::SetPointerLock(Element* aEl
   esm->SetCursor(aCursorStyle, nullptr, false,
                  0.0f, 0.0f, widget, true);
   EventStateManager::SetPointerLock(widget, aElement);
 
   return true;
 }
 
 void
-nsDocument::UnlockPointer(nsIDocument* aDoc)
+nsIDocument::UnlockPointer(nsIDocument* aDoc)
 {
   if (!EventStateManager::sIsPointerLocked) {
     return;
   }
 
   nsCOMPtr<nsIDocument> pointerLockedDoc =
     do_QueryReferent(EventStateManager::sPointerLockedDoc);
   if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
     return;
   }
-  nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
-  if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
+  if (!pointerLockedDoc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
     return;
   }
 
   nsCOMPtr<Element> pointerLockedElement =
     do_QueryReferent(EventStateManager::sPointerLockedElement);
-  ChangePointerLockedElement(nullptr, doc, pointerLockedElement);
+  ChangePointerLockedElement(nullptr, pointerLockedDoc, pointerLockedElement);
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(pointerLockedElement,
                              NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
                              true, true);
   asyncDispatcher->RunDOMEventWhenSafe();
 }
 
 void
-nsIDocument::UnlockPointer(nsIDocument* aDoc)
-{
-  nsDocument::UnlockPointer(aDoc);
-}
-
-void
 nsIDocument::UpdateVisibilityState()
 {
   dom::VisibilityState oldState = mVisibilityState;
   mVisibilityState = ComputeVisibilityState();
   if (oldState != mVisibilityState) {
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("visibilitychange"),
                                          /* bubbles = */ true,
@@ -11875,21 +11856,16 @@ nsIDocument::DocAddSizeOfExcludingThis(n
   nsINode::AddSizeOfExcludingThis(aSizes, &aSizes.mDOMOtherSize);
 
   if (mPresShell) {
     mPresShell->AddSizeOfIncludingThis(aSizes);
   }
 
   aSizes.mPropertyTablesSize +=
     mPropertyTable.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
-  for (uint32_t i = 0, count = mExtraPropertyTables.Length();
-       i < count; ++i) {
-    aSizes.mPropertyTablesSize +=
-      mExtraPropertyTables[i]->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
-  }
 
   if (EventListenerManager* elm = GetExistingListenerManager()) {
     aSizes.mDOMEventListenersCount += elm->ListenerCount();
   }
 
   if (mNodeInfoManager) {
     mNodeInfoManager->AddSizeOfIncludingThis(aSizes);
   }
@@ -12242,17 +12218,17 @@ ReportExternalResourceUseCounters(nsIDoc
 {
   const auto reportKind
     = nsDocument::UseCounterReportKind::eIncludeExternalResources;
   static_cast<nsDocument*>(aDocument)->ReportUseCounters(reportKind);
   return true;
 }
 
 void
-nsDocument::ReportUseCounters(UseCounterReportKind aKind)
+nsIDocument::ReportUseCounters(UseCounterReportKind aKind)
 {
   static const bool sDebugUseCounters = false;
   if (mReportedUseCounters) {
     return;
   }
 
   mReportedUseCounters = true;
 
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -40,17 +40,16 @@
 #include "nsIChannel.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsContentList.h"
 #include "nsGkAtoms.h"
 #include "mozilla/StyleSetHandle.h"
 #include "PLDHashTable.h"
 #include "nsDOMAttributeMap.h"
 #include "imgIRequest.h"
-#include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PendingAnimationTracker.h"
 #include "mozilla/dom/BoxObject.h"
 #include "mozilla/dom/DOMImplementation.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/dom/StyleSheetList.h"
 #include "nsDataHashtable.h"
@@ -69,17 +68,16 @@
 
 
 class nsDOMStyleSheetSetList;
 class nsDocument;
 class nsIRadioVisitor;
 class nsIFormControl;
 struct nsRadioGroupStruct;
 class nsOnloadBlocker;
-class nsUnblockOnloadEvent;
 class nsDOMNavigationTiming;
 class nsWindowSizes;
 class nsHtml5TreeOpExecutor;
 class nsDocumentOnStack;
 class nsISecurityConsoleMessage;
 
 namespace mozilla {
 class EventChainPreVisitor;
@@ -145,61 +143,34 @@ class nsDocument : public nsIDocument,
 public:
   typedef mozilla::dom::Element Element;
   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_ADDSIZEOFEXCLUDINGTHIS
 
-  virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup) override;
-  virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
-                          nsIPrincipal* aPrincipal) override;
-
-  already_AddRefed<nsIPrincipal> MaybeDowngradePrincipal(nsIPrincipal* aPrincipal);
-
   // StartDocumentLoad is pure virtual so that subclasses must override it.
   // The nsDocument StartDocumentLoad does some setup, but does NOT set
   // *aDocListener; this is the job of subclasses.
   virtual nsresult StartDocumentLoad(const char* aCommand,
                                      nsIChannel* aChannel,
                                      nsILoadGroup* aLoadGroup,
                                      nsISupports* aContainer,
                                      nsIStreamListener **aDocListener,
                                      bool aReset = true,
                                      nsIContentSink* aContentSink = nullptr) override = 0;
 
   virtual void StopDocumentLoad() override;
 
-  /**
-   * Set the Content-Type of this document.
-   */
-  virtual void SetContentType(const nsAString& aContentType) override;
-
-  /**
-   * Set the document's character encoding. This will
-   * trigger a startDocumentLoad if necessary to answer the question.
-   */
-  virtual void
-    SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding) override;
-
   static bool CallerIsTrustedAboutPage(JSContext* aCx, JSObject* aObject);
   static bool IsElementAnimateEnabled(JSContext* aCx, JSObject* aObject);
   static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject);
   static bool IsWebAnimationsEnabled(mozilla::dom::CallerType aCallerType);
 
-  virtual nsIChannel* GetFailedChannel() const override {
-    return mFailedChannel;
-  }
-  virtual void SetFailedChannel(nsIChannel* aChannel) override {
-    mFailedChannel = aChannel;
-  }
-
-  virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aGlobalObject) override;
-
   virtual void EndUpdate(nsUpdateType aUpdateType) override;
   virtual void BeginLoad() override;
   virtual void EndLoad() override;
 
   // nsIRadioGroupContainer
   NS_IMETHOD WalkRadioGroup(const nsAString& aName,
                             nsIRadioVisitor* aVisitor,
                             bool aFlushContent) override;
@@ -222,38 +193,20 @@ public:
                                        bool aRequiredAdded) override;
   virtual bool GetValueMissingState(const nsAString& aName) const override;
   virtual void SetValueMissingState(const nsAString& aName, bool aValue) override;
 
   // for radio group
   nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
   nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
 
-  enum class UseCounterReportKind {
-    // Flush the document's use counters only; the use counters for any
-    // external resource documents will be flushed when the external
-    // resource documents themselves are destroyed.
-    eDefault,
-
-    // Flush use counters for the document and for its external resource
-    // documents. (Should only be necessary for tests, where we need
-    // flushing to happen synchronously and deterministically.)
-    eIncludeExternalResources,
-  };
-
-  void ReportUseCounters(UseCounterReportKind aKind = UseCounterReportKind::eDefault);
-
-  bool IsSynthesized();
-
   // Check whether shadow DOM is enabled for the global of aObject.
   static bool IsShadowDOMEnabled(JSContext* aCx, JSObject* aObject);
   // Check whether shadow DOM is enabled for the document this node belongs to.
   static bool IsShadowDOMEnabled(const nsINode* aNode);
-private:
-  void SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages);
 
 public:
   // nsIDOMDocument
   NS_DECL_NSIDOMDOCUMENT
 
   using mozilla::dom::DocumentOrShadowRoot::GetElementById;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagName;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagNameNS;
@@ -270,22 +223,16 @@ public:
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal() override;
 
   // nsIApplicationCacheContainer
   NS_DECL_NSIAPPLICATIONCACHECONTAINER
 
   virtual nsresult Init();
 
-  virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
-                                               nsAtom* aPrefix,
-                                               int32_t aNamespaceID,
-                                               const nsAString* aIs = nullptr) override;
-
-
   virtual void Destroy() override;
   virtual void RemovedFromDocShell() override;
 
   virtual void BlockOnload() override;
   virtual void UnblockOnload(bool aFireSync) override;
 
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
                                                                    nsIDocument)
@@ -293,49 +240,19 @@ public:
   void SetLoadedAsData(bool aLoadedAsData) { mLoadedAsData = aLoadedAsData; }
   void SetLoadedAsInteractiveData(bool aLoadedAsInteractiveData)
   {
     mLoadedAsInteractiveData = aLoadedAsInteractiveData;
   }
 
   nsresult CloneDocHelper(nsDocument* clone, bool aPreallocateChildren) const;
 
-  void MaybeEndOutermostXBLUpdate();
-
   // Only BlockOnload should call this!
   void AsyncBlockOnload();
 
-  // Returns the size of the mBlockedTrackingNodes array. (nsIDocument.h)
-  //
-  // This array contains nodes that have been blocked to prevent
-  // user tracking. They most likely have had their nsIChannel
-  // canceled by the URL classifier (Safebrowsing).
-  //
-  // A script can subsequently use GetBlockedTrackingNodes()
-  // to get a list of references to these nodes.
-  //
-  // Note:
-  // This expresses how many tracking nodes have been blocked for this
-  // document since its beginning, not how many of them are still around
-  // in the DOM tree. Weak references to blocked nodes are added in the
-  // mBlockedTrackingNodesArray but they are not removed when those nodes
-  // are removed from the tree or even garbage collected.
-  long BlockedTrackingNodeCount() const;
-
-  //
-  // Returns strong references to mBlockedTrackingNodes. (nsIDocument.h)
-  //
-  // This array contains nodes that have been blocked to prevent
-  // user tracking. They most likely have had their nsIChannel
-  // canceled by the URL classifier (Safebrowsing).
-  //
-  already_AddRefed<nsSimpleContentList> BlockedTrackingNodes() const;
-
-  static void UnlockPointer(nsIDocument* aDoc = nullptr);
-
   virtual void DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const override;
   // DocAddSizeOfIncludingThis is inherited from nsIDocument.
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
 protected:
   friend class nsNodeUtils;
 
@@ -361,76 +278,40 @@ protected:
 
 #ifdef DEBUG
   void VerifyRootContentState();
 #endif
 
   explicit nsDocument(const char* aContentType);
   virtual ~nsDocument();
 
-  void EnsureOnloadBlocker();
-
 public:
   // FIXME(emilio): This needs to be here instead of in nsIDocument because Rust
   // can't represent alignas(8) values on 32-bit architectures, which would
   // cause nsIDocument's layout to be wrong in the Rust side.
   //
   // This can be fixed after updating to rust 1.25 and updating bindgen to
   // include https://github.com/rust-lang-nursery/rust-bindgen/pull/1271.
   js::ExpandoAndGeneration mExpandoAndGeneration;
 
-  RefPtr<mozilla::EventListenerManager> mListenerManager;
-
   nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
 
-  // Parser aborted. True if the parser of this document was forcibly
-  // terminated instead of letting it finish at its own pace.
-  bool mParserAborted:1;
-
   friend class nsCallRequestFullScreen;
 
-  // Whether we have reported use counters for this document with Telemetry yet.
-  // Normally this is only done at document destruction time, but for image
-  // documents (SVG documents) that are not guaranteed to be destroyed, we
-  // report use counters when the image cache no longer has any imgRequestProxys
-  // pointing to them.  We track whether we ever reported use counters so
-  // that we only report them once for the document.
-  bool mReportedUseCounters:1;
-
   // The application cache that this document is associated with, if
   // any.  This can change during the lifetime of the document.
   nsCOMPtr<nsIApplicationCache> mApplicationCache;
 
   nsCOMPtr<nsIContent> mFirstBaseNodeWithHref;
 private:
   friend class nsUnblockOnloadEvent;
 
-  void PostUnblockOnloadEvent();
-  void DoUnblockOnload();
-
-  nsresult InitCSP(nsIChannel* aChannel);
-
-  void ClearAllBoxObjects();
-
   // These are not implemented and not supported.
   nsDocument(const nsDocument& aOther);
   nsDocument& operator=(const nsDocument& aOther);
-
-  // Currently active onload blockers
-  uint32_t mOnloadBlockCount;
-  // Onload blockers which haven't been activated yet
-  uint32_t mAsyncOnloadBlockCount;
-  nsCOMPtr<nsIRequest> mOnloadBlocker;
-
-  nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner;
-
-#ifdef DEBUG
-public:
-  bool mWillReparent;
-#endif
 };
 
 class nsDocumentOnStack
 {
 public:
   explicit nsDocumentOnStack(nsIDocument* aDoc) : mDoc(aDoc)
   {
     mDoc->IncreaseStackRefCnt();
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -100,38 +100,41 @@ class nsIDOMNodeList;
 class nsIHTMLCollection;
 class nsILayoutHistoryState;
 class nsILoadContext;
 class nsIObjectLoadingContent;
 class nsIObserver;
 class nsIPrincipal;
 class nsIRequest;
 class nsIRunnable;
+class nsISecurityConsoleMessage;
 class nsIStreamListener;
 class nsIStructuredCloneContainer;
 class nsIURI;
 class nsIVariant;
 class nsViewManager;
 class nsPresContext;
 class nsRange;
 class nsSMILAnimationController;
 class nsSVGElement;
 class nsTextNode;
+class nsUnblockOnloadEvent;
 class nsWindowSizes;
 class nsDOMCaretPosition;
 class nsViewportInfo;
 class nsIGlobalObject;
 struct nsCSSSelectorList;
 
 namespace mozilla {
 class AbstractThread;
 class CSSStyleSheet;
 class Encoding;
 class ErrorResult;
 class EventStates;
+class EventListenerManager;
 class PendingAnimationTracker;
 class StyleSetHandle;
 template<typename> class OwningNonNull;
 struct URLExtraData;
 
 namespace css {
 class Loader;
 class ImageLoader;
@@ -782,17 +785,17 @@ public:
   NotNull<const Encoding*> GetDocumentCharacterSet() const
   {
     return mCharacterSet;
   }
 
   /**
    * Set the document's character encoding.
    */
-  virtual void SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding) = 0;
+  virtual void SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding);
 
   int32_t GetDocumentCharacterSetSource() const
   {
     return mCharacterSetSource;
   }
 
   // This method MUST be called before SetDocumentCharacterSet if
   // you're planning to call both.
@@ -851,17 +854,17 @@ public:
   /**
    * Get the Content-Type of this document.
    */
   void GetContentType(nsAString& aContentType);
 
   /**
    * Set the Content-Type of this document.
    */
-  virtual void SetContentType(const nsAString& aContentType) = 0;
+  virtual void SetContentType(const nsAString& aContentType);
 
   /**
    * Return the language of this document.
    */
   void GetContentLanguage(nsAString& aContentLanguage) const
   {
     CopyASCIItoUTF16(mContentLanguage, aContentLanguage);
   }
@@ -1217,23 +1220,18 @@ public:
     mBFCacheDisallowed = true;
   }
 
   bool IsBFCachingAllowed() const
   {
     return !mBFCacheDisallowed;
   }
 
-  void SetBFCacheEntry(nsIBFCacheEntry* aEntry)
-  {
-    NS_ASSERTION(IsBFCachingAllowed() || !aEntry,
-                 "You should have checked!");
-
-    mBFCacheEntry = aEntry;
-  }
+  // Accepts null to clear the BFCache entry too.
+  void SetBFCacheEntry(nsIBFCacheEntry* aEntry);
 
   nsIBFCacheEntry* GetBFCacheEntry() const
   {
     return mBFCacheEntry;
   }
 
   /**
    * Return the parent document of this document. Will return null
@@ -1399,17 +1397,58 @@ public:
 
   // Resolve all SVG pres attrs scheduled in ScheduleSVGForPresAttrEvaluation
   void ResolveScheduledSVGPresAttrs();
 
   mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
   mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
   mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
 
+  // Returns the size of the mBlockedTrackingNodes array.
+  //
+  // This array contains nodes that have been blocked to prevent
+  // user tracking. They most likely have had their nsIChannel
+  // canceled by the URL classifier (Safebrowsing).
+  //
+  // A script can subsequently use GetBlockedTrackingNodes()
+  // to get a list of references to these nodes.
+  //
+  // Note:
+  // This expresses how many tracking nodes have been blocked for this
+  // document since its beginning, not how many of them are still around
+  // in the DOM tree. Weak references to blocked nodes are added in the
+  // mBlockedTrackingNodesArray but they are not removed when those nodes
+  // are removed from the tree or even garbage collected.
+  long BlockedTrackingNodeCount() const
+  {
+    return mBlockedTrackingNodes.Length();
+  }
+
+  //
+  // Returns strong references to mBlockedTrackingNodes. (nsIDocument.h)
+  //
+  // This array contains nodes that have been blocked to prevent
+  // user tracking. They most likely have had their nsIChannel
+  // canceled by the URL classifier (Safebrowsing).
+  //
+  already_AddRefed<nsSimpleContentList> BlockedTrackingNodes() const;
+
 protected:
+  friend class nsUnblockOnloadEvent;
+
+  nsresult InitCSP(nsIChannel* aChannel);
+
+  void PostUnblockOnloadEvent();
+
+  void DoUnblockOnload();
+
+  void ClearAllBoxObjects();
+
+  void MaybeEndOutermostXBLUpdate();
+
   void DispatchContentLoadedEvents();
 
   void DispatchPageTransition(mozilla::dom::EventTarget* aDispatchTarget,
                               const nsAString& aType,
                               bool aPersisted);
 
   // Call this before the document does something that will unbind all content.
   // That will stop us from doing a lot of work as each element is removed.
@@ -1758,17 +1797,17 @@ public:
   /**
    * Get this document's inline style sheet.  May return null if there
    * isn't one
    */
   nsHTMLCSSStyleSheet* GetInlineStyleSheet() const {
     return mStyleAttrStyleSheet;
   }
 
-  virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aGlobalObject) = 0;
+  virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aGlobalObject);
 
   /**
    * Get/set the object from which the context for the event/script handling can
    * be got. Normally GetScriptHandlingObject() returns the same object as
    * GetScriptGlobalObject(), but if the document is loaded as data,
    * non-null may be returned, even if GetScriptGlobalObject() returns null.
    * aHasHadScriptHandlingObject is set true if document has had the object
    * for event/script handling. Do not process any events/script if the method
@@ -2094,25 +2133,26 @@ public:
     return mNodeInfoManager;
   }
 
   /**
    * Reset the document using the given channel and loadgroup.  This works
    * like ResetToURI, but also sets the document's channel to aChannel.
    * The principal of the document will be set from the channel.
    */
-  virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) = 0;
+  virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
 
   /**
    * Reset this document to aURI, aLoadGroup, and aPrincipal.  aURI must not be
    * null.  If aPrincipal is null, a codebase principal based on aURI will be
    * used.
    */
-  virtual void ResetToURI(nsIURI *aURI, nsILoadGroup* aLoadGroup,
-                          nsIPrincipal* aPrincipal) = 0;
+  virtual void ResetToURI(nsIURI* aURI,
+                          nsILoadGroup* aLoadGroup,
+                          nsIPrincipal* aPrincipal);
 
   /**
    * Set the container (docshell) for this document. Virtual so that
    * docshell can call it.
    */
   virtual void SetContainer(nsDocShell* aContainer);
 
   /**
@@ -2197,20 +2237,20 @@ public:
   {
     mIsContentDocument = aIsContentDocument;
   }
 
   /**
    * Create an element with the specified name, prefix and namespace ID.
    * Returns null if element name parsing failed.
    */
-  virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
-                                               nsAtom* aPrefix,
-                                               int32_t aNamespaceID,
-                                               const nsAString* aIs = nullptr) = 0;
+  already_AddRefed<Element> CreateElem(const nsAString& aName,
+                                       nsAtom* aPrefix,
+                                       int32_t aNamespaceID,
+                                       const nsAString* aIs = nullptr);
 
   /**
    * Get the security info (i.e. SSL state etc) that the document got
    * from the channel/document that created the content of the
    * document.
    *
    * @see nsIChannel
    */
@@ -2218,43 +2258,46 @@ public:
   {
     return mSecurityInfo;
   }
 
   /**
    * Get the channel that failed to load and resulted in an error page, if it
    * exists. This is only relevant to error pages.
    */
-  virtual nsIChannel* GetFailedChannel() const = 0;
+  nsIChannel* GetFailedChannel() const
+  {
+    return mFailedChannel;
+  }
 
   /**
    * Set the channel that failed to load and resulted in an error page.
    * This is only relevant to error pages.
    */
-  virtual void SetFailedChannel(nsIChannel* aChannel) = 0;
+  void SetFailedChannel(nsIChannel* aChannel)
+  {
+    mFailedChannel = aChannel;
+  }
 
   /**
    * Returns the default namespace ID used for elements created in this
    * document.
    */
   int32_t GetDefaultNamespaceID() const
   {
     return mDefaultElementType;
   }
 
   void DeleteAllProperties();
   void DeleteAllPropertiesFor(nsINode* aNode);
 
-  nsPropertyTable* PropertyTable(uint16_t aCategory) {
-    if (aCategory == 0)
-      return &mPropertyTable;
-    return GetExtraPropertyTable(aCategory);
-  }
-  uint32_t GetPropertyTableCount()
-  { return mExtraPropertyTables.Length() + 1; }
+  nsPropertyTable& PropertyTable()
+  {
+    return mPropertyTable;
+  }
 
   /**
    * Sets the ID used to identify this part of the multipart document
    */
   void SetPartID(uint32_t aID) {
     mPartID = aID;
   }
 
@@ -3454,16 +3497,32 @@ public:
   void MarkUserFontSetDirty();
   mozilla::dom::FontFaceSet* GetFonts() { return mFontFaceSet; }
 
   // FontFaceSource
   mozilla::dom::FontFaceSet* Fonts();
 
   bool DidFireDOMContentLoaded() const { return mDidFireDOMContentLoaded; }
 
+  bool IsSynthesized();
+
+  enum class UseCounterReportKind {
+    // Flush the document's use counters only; the use counters for any
+    // external resource documents will be flushed when the external
+    // resource documents themselves are destroyed.
+    eDefault,
+
+    // Flush use counters for the document and for its external resource
+    // documents. (Should only be necessary for tests, where we need
+    // flushing to happen synchronously and deterministically.)
+    eIncludeExternalResources,
+  };
+
+  void ReportUseCounters(UseCounterReportKind aKind = UseCounterReportKind::eDefault);
+
   void SetDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
     if (!mUseCounters[aUseCounter]) {
       mUseCounters[aUseCounter] = true;
     }
   }
 
   void SetPageUseCounter(mozilla::UseCounter aUseCounter);
@@ -3626,16 +3685,22 @@ public:
    * anonymous. Otherwise, when aFrame is in a subdocument, we use the frame
    * element containing the subdocument containing aFrame, and/or find the
    * nearest non-anonymous ancestor in this document.
    * Returns null if there is no such element.
    */
   nsIContent* GetContentInThisDocument(nsIFrame* aFrame) const;
 
 protected:
+  already_AddRefed<nsIPrincipal> MaybeDowngradePrincipal(nsIPrincipal* aPrincipal);
+
+  void EnsureOnloadBlocker();
+
+  void SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages);
+
   // Returns true if the scheme for the url for this document is "about".
   bool IsAboutPage() const;
 
   bool ContainsEMEContent();
   bool ContainsMSEContent();
 
   void MaybeInitializeFinalizeFrameLoaders();
 
@@ -3734,17 +3799,16 @@ protected:
   {
     if (--mStackRefCnt == 0 && mNeedsReleaseAfterStackRefCntRelease) {
       mNeedsReleaseAfterStackRefCntRelease = false;
       NS_RELEASE_THIS();
     }
   }
 
   ~nsIDocument();
-  nsPropertyTable* GetExtraPropertyTable(uint16_t aCategory);
 
   // Never ever call this. Only call GetWindow!
   nsPIDOMWindowOuter* GetWindowInternal() const;
 
   // Never ever call this. Only call GetScriptHandlingObject!
   nsIScriptGlobalObject* GetScriptHandlingObjectInternal() const;
 
   // Never ever call this. Only call AllowXULXBL!
@@ -3876,17 +3940,16 @@ protected:
 
   LinksToUpdateList mLinksToUpdate;
 
   // SMIL Animation Controller, lazily-initialized in GetAnimationController
   RefPtr<nsSMILAnimationController> mAnimationController;
 
   // Table of element properties for this document.
   nsPropertyTable mPropertyTable;
-  nsTArray<nsAutoPtr<nsPropertyTable> > mExtraPropertyTables;
 
   // Our cached .children collection
   nsCOMPtr<nsIHTMLCollection> mChildrenCollection;
 
   // Various DOM lists
   RefPtr<nsContentList> mImages;
   RefPtr<nsContentList> mEmbeds;
   RefPtr<nsContentList> mLinks;
@@ -4136,20 +4199,44 @@ protected:
   bool mAutoSize: 1;
   bool mAllowZoom: 1;
   bool mAllowDoubleTapZoom: 1;
   bool mValidScaleFloat: 1;
   bool mValidMaxScale: 1;
   bool mScaleStrEmpty: 1;
   bool mWidthStrEmpty: 1;
 
+  // Parser aborted. True if the parser of this document was forcibly
+  // terminated instead of letting it finish at its own pace.
+  bool mParserAborted: 1;
+
+  // Whether we have reported use counters for this document with Telemetry yet.
+  // Normally this is only done at document destruction time, but for image
+  // documents (SVG documents) that are not guaranteed to be destroyed, we
+  // report use counters when the image cache no longer has any imgRequestProxys
+  // pointing to them.  We track whether we ever reported use counters so
+  // that we only report them once for the document.
+  bool mReportedUseCounters: 1;
+
+#ifdef DEBUG
+public:
+  bool mWillReparent: 1;
+protected:
+#endif
+
   uint8_t mPendingFullscreenRequests;
 
   uint8_t mXMLDeclarationBits;
 
+  // Currently active onload blockers.
+  uint32_t mOnloadBlockCount;
+
+  // Onload blockers which haven't been activated yet.
+  uint32_t mAsyncOnloadBlockCount;
+
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState
   ReadyState mReadyState;
 
   // Whether this document has (or will have, once we have a pres shell) a
   // Gecko- or Servo-backed style system.
@@ -4459,16 +4546,21 @@ protected:
   // These member variables cache information about the viewport so we don't
   // have to recalculate it each time.
   mozilla::LayoutDeviceToScreenScale mScaleMinFloat;
   mozilla::LayoutDeviceToScreenScale mScaleMaxFloat;
   mozilla::LayoutDeviceToScreenScale mScaleFloat;
   mozilla::CSSToLayoutDeviceScale mPixelRatio;
   mozilla::CSSSize mViewportSize;
 
+  RefPtr<mozilla::EventListenerManager> mListenerManager;
+
+  nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner;
+  nsCOMPtr<nsIRequest> mOnloadBlocker;
+
   nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
   nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
 
   // Member to store out last-selected stylesheet set.
   nsString mLastStyleSheetSet;
   RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
 
   // We lazily calculate declaration blocks for SVG elements with mapped
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -160,60 +160,56 @@ nsINode::nsSlots::Unlink()
 
 nsINode::~nsINode()
 {
   MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
   MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
 }
 
 void*
-nsINode::GetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                     nsresult *aStatus) const
+nsINode::GetProperty(nsAtom* aPropertyName, nsresult* aStatus) const
 {
   if (!HasProperties()) { // a fast HasFlag() test
     if (aStatus) {
       *aStatus = NS_PROPTABLE_PROP_NOT_THERE;
     }
     return nullptr;
   }
-  return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
-                                                           aStatus);
+  return OwnerDoc()->PropertyTable().GetProperty(this, aPropertyName, aStatus);
 }
 
 nsresult
-nsINode::SetProperty(uint16_t aCategory, nsAtom *aPropertyName, void *aValue,
-                     NSPropertyDtorFunc aDtor, bool aTransfer,
-                     void **aOldValue)
+nsINode::SetProperty(nsAtom* aPropertyName,
+                     void* aValue,
+                     NSPropertyDtorFunc aDtor,
+                     bool aTransfer)
 {
-  nsresult rv = OwnerDoc()->PropertyTable(aCategory)->SetProperty(this,
-                                                                  aPropertyName,
-                                                                  aValue, aDtor,
-                                                                  nullptr,
-                                                                  aTransfer,
-                                                                  aOldValue);
+  nsresult rv = OwnerDoc()->PropertyTable().SetProperty(this,
+                                                        aPropertyName,
+                                                        aValue,
+                                                        aDtor,
+                                                        nullptr,
+                                                        aTransfer);
   if (NS_SUCCEEDED(rv)) {
     SetFlags(NODE_HAS_PROPERTIES);
   }
 
   return rv;
 }
 
 void
-nsINode::DeleteProperty(uint16_t aCategory, nsAtom *aPropertyName)
+nsINode::DeleteProperty(nsAtom* aPropertyName)
 {
-  OwnerDoc()->PropertyTable(aCategory)->DeleteProperty(this, aPropertyName);
+  OwnerDoc()->PropertyTable().DeleteProperty(this, aPropertyName);
 }
 
 void*
-nsINode::UnsetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                       nsresult *aStatus)
+nsINode::UnsetProperty(nsAtom* aPropertyName, nsresult* aStatus)
 {
-  return OwnerDoc()->PropertyTable(aCategory)->UnsetProperty(this,
-                                                             aPropertyName,
-                                                             aStatus);
+  return OwnerDoc()->PropertyTable().UnsetProperty(this, aPropertyName, aStatus);
 }
 
 nsINode::nsSlots*
 nsINode::CreateSlots()
 {
   return new nsSlots();
 }
 
@@ -731,113 +727,16 @@ nsINode::LookupPrefix(const nsAString& a
         }
       }
     }
   }
 
   SetDOMStringToNull(aPrefix);
 }
 
-static nsresult
-SetUserDataProperty(uint16_t aCategory, nsINode *aNode, nsAtom *aKey,
-                    nsISupports* aValue, void** aOldValue)
-{
-  nsresult rv = aNode->SetProperty(aCategory, aKey, aValue,
-                                   nsPropertyTable::SupportsDtorFunc, true,
-                                   aOldValue);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Property table owns it now.
-  NS_ADDREF(aValue);
-
-  return NS_OK;
-}
-
-nsresult
-nsINode::SetUserData(const nsAString &aKey, nsIVariant *aData, nsIVariant **aResult)
-{
-  OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData);
-  *aResult = nullptr;
-
-  RefPtr<nsAtom> key = NS_Atomize(aKey);
-  if (!key) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsresult rv;
-  void *data;
-  if (aData) {
-    rv = SetUserDataProperty(DOM_USER_DATA, this, key, aData, &data);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    data = UnsetProperty(DOM_USER_DATA, key);
-  }
-
-  // Take over ownership of the old data from the property table.
-  nsCOMPtr<nsIVariant> oldData = dont_AddRef(static_cast<nsIVariant*>(data));
-  oldData.swap(*aResult);
-  return NS_OK;
-}
-
-void
-nsINode::SetUserData(JSContext* aCx, const nsAString& aKey,
-                     JS::Handle<JS::Value> aData,
-                     JS::MutableHandle<JS::Value> aRetval,
-                     ErrorResult& aError)
-{
-  nsCOMPtr<nsIVariant> data;
-  aError = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData, getter_AddRefs(data));
-  if (aError.Failed()) {
-    return;
-  }
-
-  nsCOMPtr<nsIVariant> oldData;
-  aError = SetUserData(aKey, data, getter_AddRefs(oldData));
-  if (aError.Failed()) {
-    return;
-  }
-
-  if (!oldData) {
-    aRetval.setNull();
-    return;
-  }
-
-  JSAutoCompartment ac(aCx, GetWrapper());
-  aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), oldData,
-                                                    aRetval);
-}
-
-nsIVariant*
-nsINode::GetUserData(const nsAString& aKey)
-{
-  OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData);
-  RefPtr<nsAtom> key = NS_Atomize(aKey);
-  if (!key) {
-    return nullptr;
-  }
-
-  return static_cast<nsIVariant*>(GetProperty(DOM_USER_DATA, key));
-}
-
-void
-nsINode::GetUserData(JSContext* aCx, const nsAString& aKey,
-                     JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
-{
-  nsIVariant* data = GetUserData(aKey);
-  if (!data) {
-    aRetval.setNull();
-    return;
-  }
-
-  JSAutoCompartment ac(aCx, GetWrapper());
-  aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), data,
-                                                    aRetval);
-}
-
 uint16_t
 nsINode::CompareDocumentPosition(nsINode& aOtherNode) const
 {
   if (this == &aOtherNode) {
     return 0;
   }
   if (GetPreviousSibling() == &aOtherNode) {
     MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode());
@@ -1407,17 +1306,16 @@ nsINode::Traverse(nsINode *tmp, nsCycleC
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
 
   nsSlots *slots = tmp->GetExistingSlots();
   if (slots) {
     slots->Traverse(cb);
   }
 
   if (tmp->HasProperties()) {
-    nsNodeUtils::TraverseUserData(tmp, cb);
     nsCOMArray<nsISupports>* objects =
       static_cast<nsCOMArray<nsISupports>*>(tmp->GetProperty(nsGkAtoms::keepobjectsalive));
     if (objects) {
       for (int32_t i = 0; i < objects->Count(); ++i) {
          cb.NoteXPCOMChild(objects->ObjectAt(i));
       }
     }
   }
@@ -1443,17 +1341,16 @@ nsINode::Unlink(nsINode* tmp)
 
   if (tmp->NodeType() != DOCUMENT_NODE &&
       tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
     nsContentUtils::RemoveListenerManager(tmp);
     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
   }
 
   if (tmp->HasProperties()) {
-    nsNodeUtils::UnlinkUserData(tmp);
     tmp->DeleteProperty(nsGkAtoms::keepobjectsalive);
   }
 }
 
 static void
 AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode, ErrorResult& aError)
 {
   NS_ASSERTION(!aNode->GetParentNode(),
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -268,20 +268,16 @@ private:
 // This should be used for any nsINode sub-class that has fields of its own
 // that it needs to measure; any sub-class that doesn't use it will inherit
 // AddSizeOfExcludingThis from its super-class. AddSizeOfIncludingThis() need
 // not be defined, it is inherited from nsINode.
 #define NS_DECL_ADDSIZEOFEXCLUDINGTHIS \
   virtual void AddSizeOfExcludingThis(nsWindowSizes& aSizes, \
                                       size_t* aNodeSize) const override;
 
-// Categories of node properties
-// 0 is global.
-#define DOM_USER_DATA         1
-
 // IID for the nsINode interface
 // Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
 #define NS_INODE_IID \
 { 0x70ba4547, 0x7699, 0x44fc, \
   { 0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
@@ -839,36 +835,17 @@ public:
    * @param aPropertyName  name of property to get.
    * @param aStatus        out parameter for storing resulting status.
    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
    *                       is not set.
    * @return               the property. Null if the property is not set
    *                       (though a null return value does not imply the
    *                       property was not set, i.e. it can be set to null).
    */
-  void* GetProperty(nsAtom *aPropertyName,
-                    nsresult *aStatus = nullptr) const
-  {
-    return GetProperty(0, aPropertyName, aStatus);
-  }
-
-  /**
-   * Get a property associated with this node.
-   *
-   * @param aCategory      category of property to get.
-   * @param aPropertyName  name of property to get.
-   * @param aStatus        out parameter for storing resulting status.
-   *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
-   *                       is not set.
-   * @return               the property. Null if the property is not set
-   *                       (though a null return value does not imply the
-   *                       property was not set, i.e. it can be set to null).
-   */
-  void* GetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                    nsresult *aStatus = nullptr) const;
+  void* GetProperty(nsAtom* aPropertyName, nsresult* aStatus = nullptr) const;
 
   /**
    * Set a property to be associated with this node. This will overwrite an
    * existing value if one exists. The existing value is destroyed using the
    * destructor function given when that value was set.
    *
    * @param aPropertyName  name of property to set.
    * @param aValue         new value of property.
@@ -877,112 +854,52 @@ public:
    * @param aTransfer      if true the property will not be deleted when the
    *                       ownerDocument of the node changes, if false it
    *                       will be deleted.
    *
    * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
    *                                       was already set
    * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
    */
-  nsresult SetProperty(nsAtom *aPropertyName, void *aValue,
+  nsresult SetProperty(nsAtom* aPropertyName,
+                       void* aValue,
                        NSPropertyDtorFunc aDtor = nullptr,
-                       bool aTransfer = false)
-  {
-    return SetProperty(0, aPropertyName, aValue, aDtor, aTransfer);
-  }
-
-  /**
-   * Set a property to be associated with this node. This will overwrite an
-   * existing value if one exists. The existing value is destroyed using the
-   * destructor function given when that value was set.
-   *
-   * @param aCategory       category of property to set.
-   * @param aPropertyName   name of property to set.
-   * @param aValue          new value of property.
-   * @param aDtor           destructor function to be used when this property
-   *                        is destroyed.
-   * @param aTransfer       if true the property will not be deleted when the
-   *                        ownerDocument of the node changes, if false it
-   *                        will be deleted.
-   * @param aOldValue [out] previous value of property.
-   *
-   * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
-   *                                       was already set
-   * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
-   */
-  nsresult SetProperty(uint16_t aCategory,
-                       nsAtom *aPropertyName, void *aValue,
-                       NSPropertyDtorFunc aDtor = nullptr,
-                       bool aTransfer = false,
-                       void **aOldValue = nullptr);
+                       bool aTransfer = false);
 
   /**
    * A generic destructor for property values allocated with new.
    */
   template<class T>
-  static void DeleteProperty(void *, nsAtom *, void *aPropertyValue, void *)
+  static void DeleteProperty(void*, nsAtom*, void* aPropertyValue, void*)
   {
     delete static_cast<T *>(aPropertyValue);
   }
 
   /**
    * Destroys a property associated with this node. The value is destroyed
    * using the destruction function given when that value was set.
    *
    * @param aPropertyName  name of property to destroy.
    */
-  void DeleteProperty(nsAtom *aPropertyName)
-  {
-    DeleteProperty(0, aPropertyName);
-  }
-
-  /**
-   * Destroys a property associated with this node. The value is destroyed
-   * using the destruction function given when that value was set.
-   *
-   * @param aCategory      category of property to destroy.
-   * @param aPropertyName  name of property to destroy.
-   */
-  void DeleteProperty(uint16_t aCategory, nsAtom *aPropertyName);
+  void DeleteProperty(nsAtom* aPropertyName);
 
   /**
    * Unset a property associated with this node. The value will not be
    * destroyed but rather returned. It is the caller's responsibility to
    * destroy the value after that point.
    *
    * @param aPropertyName  name of property to unset.
    * @param aStatus        out parameter for storing resulting status.
    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
    *                       is not set.
    * @return               the property. Null if the property is not set
    *                       (though a null return value does not imply the
    *                       property was not set, i.e. it can be set to null).
    */
-  void* UnsetProperty(nsAtom  *aPropertyName,
-                      nsresult *aStatus = nullptr)
-  {
-    return UnsetProperty(0, aPropertyName, aStatus);
-  }
-
-  /**
-   * Unset a property associated with this node. The value will not be
-   * destroyed but rather returned. It is the caller's responsibility to
-   * destroy the value after that point.
-   *
-   * @param aCategory      category of property to unset.
-   * @param aPropertyName  name of property to unset.
-   * @param aStatus        out parameter for storing resulting status.
-   *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
-   *                       is not set.
-   * @return               the property. Null if the property is not set
-   *                       (though a null return value does not imply the
-   *                       property was not set, i.e. it can be set to null).
-   */
-  void* UnsetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                      nsresult *aStatus = nullptr);
+  void* UnsetProperty(nsAtom* aPropertyName, nsresult* aStatus = nullptr);
 
   bool HasProperties() const
   {
     return HasFlag(NODE_HAS_PROPERTIES);
   }
 
   /**
    * Return the principal of this node.  This is guaranteed to never be a null
@@ -1446,41 +1363,16 @@ public:
   already_AddRefed<nsINodeList> QuerySelectorAll(const nsAString& aSelector,
                                                  mozilla::ErrorResult& aResult);
 
 protected:
   // nsIDocument overrides this with its own (faster) version.  This
   // should really only be called for elements and document fragments.
   mozilla::dom::Element* GetElementById(const nsAString& aId);
 
-  /**
-   * Associate an object aData to aKey on this node. If aData is null any
-   * previously registered object associated to aKey on this node will
-   * be removed.
-   * Should only be used to implement the DOM Level 3 UserData API.
-   *
-   * @param aKey the key to associate the object to
-   * @param aData the object to associate to aKey on this node (may be null)
-   * @param aResult [out] the previously registered object for aKey on this
-   *                      node, if any
-   * @return whether adding the object succeeded
-   */
-  nsresult SetUserData(const nsAString& aKey, nsIVariant* aData,
-                       nsIVariant** aResult);
-
-  /**
-   * Get the UserData object registered for a Key on this node, if any.
-   * Should only be used to implement the DOM Level 3 UserData API.
-   *
-   * @param aKey the key to get UserData for
-   * @return aResult the previously registered object for aKey on this node, if
-   *                 any
-   */
-  nsIVariant* GetUserData(const nsAString& aKey);
-
 public:
   void LookupPrefix(const nsAString& aNamespace, nsAString& aResult);
   bool IsDefaultNamespace(const nsAString& aNamespaceURI)
   {
     nsAutoString defaultNamespace;
     LookupNamespaceURI(EmptyString(), defaultNamespace);
     return aNamespaceURI.Equals(defaultNamespace);
   }
@@ -1939,23 +1831,16 @@ public:
 #endif
   void GetLocalName(mozilla::dom::DOMString& aLocalName) const
   {
     const nsString& localName = LocalName();
     aLocalName.SetKnownLiveString(localName);
   }
 
   nsDOMAttributeMap* GetAttributes();
-  void SetUserData(JSContext* aCx, const nsAString& aKey,
-                   JS::Handle<JS::Value> aData,
-                   JS::MutableHandle<JS::Value> aRetval,
-                   mozilla::ErrorResult& aError);
-  void GetUserData(JSContext* aCx, const nsAString& aKey,
-                   JS::MutableHandle<JS::Value> aRetval,
-                   mozilla::ErrorResult& aError);
 
   // Helper method to remove this node from its parent. This is not exposed
   // through WebIDL.
   // Only call this if the node has a parent node.
   nsresult RemoveFromParent()
   {
     nsINode* parent = GetParentNode();
     mozilla::ErrorResult rv;
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -365,34 +365,16 @@ nsNodeUtils::LastRelease(nsINode* aNode)
                  "Node has binding on destruction");
   }
 
   aNode->ReleaseWrapper(aNode);
 
   FragmentOrElement::RemoveBlackMarkedNode(aNode);
 }
 
-static void
-NoteUserData(void *aObject, nsAtom *aKey, void *aXPCOMChild, void *aData)
-{
-  nsCycleCollectionTraversalCallback* cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aData);
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "[user data]");
-  cb->NoteXPCOMChild(static_cast<nsISupports*>(aXPCOMChild));
-}
-
-/* static */
-void
-nsNodeUtils::TraverseUserData(nsINode* aNode,
-                              nsCycleCollectionTraversalCallback &aCb)
-{
-  nsIDocument* ownerDoc = aNode->OwnerDoc();
-  ownerDoc->PropertyTable(DOM_USER_DATA)->Enumerate(aNode, NoteUserData, &aCb);
-}
-
 /* static */
 already_AddRefed<nsINode>
 nsNodeUtils::CloneNodeImpl(nsINode *aNode, bool aDeep, ErrorResult& aError)
 {
   return Clone(aNode, aDeep, nullptr, nullptr, aError);
 }
 
 /* static */
@@ -711,29 +693,16 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
         return nullptr;
       }
     }
   }
 
   return clone.forget();
 }
 
-
-/* static */
-void
-nsNodeUtils::UnlinkUserData(nsINode *aNode)
-{
-  NS_ASSERTION(aNode->HasProperties(), "Call to UnlinkUserData not needed.");
-
-  // Strong reference to the document so that deleting properties can't
-  // delete the document.
-  nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
-  document->PropertyTable(DOM_USER_DATA)->DeleteAllPropertiesFor(aNode);
-}
-
 bool
 nsNodeUtils::IsTemplateElement(const nsINode *aNode)
 {
   return aNode->IsHTMLElement(nsGkAtoms::_template);
 }
 
 nsIContent*
 nsNodeUtils::GetFirstChildOfTemplateOrNode(nsINode* aNode)
--- a/dom/base/nsNodeUtils.h
+++ b/dom/base/nsNodeUtils.h
@@ -220,45 +220,29 @@ public:
     nsCOMPtr<nsINode> node = CloneAndAdopt(aNode, false, true, aNewNodeInfoManager,
                                            aReparentScope, &aNodesWithProperties,
                                            nullptr, aError);
 
     nsMutationGuard::DidMutate();
   }
 
   /**
-   * Helper for the cycle collector to traverse the DOM UserData for aNode.
-   *
-   * @param aNode the node to traverse UserData for
-   * @param aCb the cycle collection callback
-   */
-  static void TraverseUserData(nsINode* aNode,
-                               nsCycleCollectionTraversalCallback &aCb);
-
-  /**
    * A basic implementation of the DOM cloneNode method. Calls nsINode::Clone to
    * do the actual cloning of the node.
    *
    * @param aNode the node to clone
    * @param aDeep if true all descendants will be cloned too
    * @param aError the error, if any.
    *
    * @return the clone, or null if an error occurs.
    */
   static already_AddRefed<nsINode> CloneNodeImpl(nsINode *aNode, bool aDeep,
                                                  mozilla::ErrorResult& aError);
 
   /**
-   * Release the UserData for aNode.
-   *
-   * @param aNode the node to release the UserData for
-   */
-  static void UnlinkUserData(nsINode *aNode);
-
-  /**
    * Returns a true if the node is a HTMLTemplate element.
    *
    * @param aNode a node to test for HTMLTemplate elementness.
    */
   static bool IsTemplateElement(const nsINode *aNode);
 
   /**
    * Returns the first child of a node or the first child of
--- a/dom/base/nsPropertyTable.cpp
+++ b/dom/base/nsPropertyTable.cpp
@@ -75,38 +75,36 @@ nsPropertyTable::DeleteAllPropertiesFor(
 {
   for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
     prop->DeletePropertyFor(aObject);
   }
 }
 
 nsresult
 nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
-                                                  nsPropertyTable *aOtherTable)
+                                                  nsPropertyTable& aOtherTable)
 {
   nsresult rv = NS_OK;
   for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
     if (prop->mTransfer) {
       auto entry = static_cast<PropertyListMapEntry*>
                               (prop->mObjectValueMap.Search(aObject));
       if (entry) {
-        rv = aOtherTable->SetProperty(aObject, prop->mName,
-                                      entry->value, prop->mDtorFunc,
-                                      prop->mDtorData, prop->mTransfer);
+        rv = aOtherTable.SetProperty(aObject, prop->mName,
+                                     entry->value, prop->mDtorFunc,
+                                     prop->mDtorData, prop->mTransfer);
         if (NS_FAILED(rv)) {
           DeleteAllPropertiesFor(aObject);
-          aOtherTable->DeleteAllPropertiesFor(aObject);
-
+          aOtherTable.DeleteAllPropertiesFor(aObject);
           break;
         }
 
         prop->mObjectValueMap.RemoveEntry(entry);
       }
-    }
-    else {
+    } else {
       prop->DeletePropertyFor(aObject);
     }
   }
 
   return rv;
 }
 
 void
@@ -133,19 +131,19 @@ nsPropertyTable::EnumerateAll(NSProperty
       aCallBack(const_cast<void*>(entry->key), prop->mName, entry->value,
                 aData);
     }
   }
 }
 
 void*
 nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
-                                     nsAtom    *aPropertyName,
-                                     bool        aRemove,
-                                     nsresult   *aResult)
+                                     nsAtom* aPropertyName,
+                                     bool aRemove,
+                                     nsresult* aResult)
 {
   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
   nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
   void *propValue = nullptr;
 
   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
   if (propertyList) {
     auto entry = static_cast<PropertyListMapEntry*>
@@ -162,23 +160,22 @@ nsPropertyTable::GetPropertyInternal(nsP
 
   if (aResult)
     *aResult = rv;
 
   return propValue;
 }
 
 nsresult
-nsPropertyTable::SetPropertyInternal(nsPropertyOwner     aObject,
-                                     nsAtom            *aPropertyName,
-                                     void               *aPropertyValue,
-                                     NSPropertyDtorFunc  aPropDtorFunc,
-                                     void               *aPropDtorData,
-                                     bool                aTransfer,
-                                     void              **aOldValue)
+nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
+                                     nsAtom* aPropertyName,
+                                     void* aPropertyValue,
+                                     NSPropertyDtorFunc aPropDtorFunc,
+                                     void* aPropDtorData,
+                                     bool aTransfer)
 {
   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
 
   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
 
   if (propertyList) {
     // Make sure the dtor function and data and the transfer flag match
     if (aPropDtorFunc != propertyList->mDtorFunc ||
@@ -200,35 +197,31 @@ nsPropertyTable::SetPropertyInternal(nsP
   nsresult result = NS_OK;
   auto entry = static_cast<PropertyListMapEntry*>
     (propertyList->mObjectValueMap.Add(aObject, mozilla::fallible));
   if (!entry)
     return NS_ERROR_OUT_OF_MEMORY;
   // A nullptr entry->key is the sign that the entry has just been allocated
   // for us.  If it's non-nullptr then we have an existing entry.
   if (entry->key) {
-    if (aOldValue)
-      *aOldValue = entry->value;
-    else if (propertyList->mDtorFunc)
+    if (propertyList->mDtorFunc) {
       propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
                               entry->value, propertyList->mDtorData);
+    }
     result = NS_PROPTABLE_PROP_OVERWRITTEN;
   }
-  else if (aOldValue) {
-    *aOldValue = nullptr;
-  }
   entry->key = aObject;
   entry->value = aPropertyValue;
 
   return result;
 }
 
 nsresult
 nsPropertyTable::DeleteProperty(nsPropertyOwner aObject,
-                                nsAtom    *aPropertyName)
+                                nsAtom* aPropertyName)
 {
   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
 
   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
   if (propertyList) {
     if (propertyList->DeletePropertyFor(aObject))
       return NS_OK;
   }
--- a/dom/base/nsPropertyTable.h
+++ b/dom/base/nsPropertyTable.h
@@ -70,52 +70,48 @@ class nsPropertyTable
   /**
    * Set the value of the property |aPropertyName| to
    * |aPropertyValue| for node |aObject|.  |aDtor| is a destructor for the
    * property value to be called if the property is removed.  It can be null
    * if no destructor is required.  |aDtorData| is an optional pointer to an
    * opaque context to be passed to the property destructor.  Note that the
    * destructor is global for each property name regardless of node; it is an
    * error to set a given property with a different destructor than was used
-   * before (this will return NS_ERROR_INVALID_ARG). If aOldValue is non-null
-   * it will contain the old value after the function returns (the destructor
-   * for the old value will not be run in that case). If |aTransfer| is true
+   * before (this will return NS_ERROR_INVALID_ARG). If |aTransfer| is true
    * the property will be transfered to the new table when the property table
    * for |aObject| changes (currently the tables for nodes are owned by their
    * ownerDocument, so if the ownerDocument for a node changes, its property
    * table changes too). If |aTransfer| is false the property will just be
    * deleted instead.
    */
-  nsresult SetProperty(const nsPropertyOwner&     aObject,
-                                   nsAtom            *aPropertyName,
-                                   void               *aPropertyValue,
-                                   NSPropertyDtorFunc  aDtor,
-                                   void               *aDtorData,
-                                   bool                aTransfer = false,
-                                   void              **aOldValue = nullptr)
+  nsresult SetProperty(const nsPropertyOwner& aObject,
+                       nsAtom* aPropertyName,
+                       void* aPropertyValue,
+                       NSPropertyDtorFunc aDtor,
+                       void* aDtorData,
+                       bool aTransfer = false)
   {
     return SetPropertyInternal(aObject, aPropertyName, aPropertyValue,
-                               aDtor, aDtorData, aTransfer, aOldValue);
+                               aDtor, aDtorData, aTransfer);
   }
 
   /**
    * Delete the property |aPropertyName| in the global category for object
    * |aObject|. The property's destructor function will be called.
    */
-  nsresult DeleteProperty(nsPropertyOwner aObject,
-                                      nsAtom    *aPropertyName);
+  nsresult DeleteProperty(nsPropertyOwner aObject, nsAtom* aPropertyName);
 
   /**
    * Unset the property |aPropertyName| in the global category for object
    * |aObject|, but do not call the property's destructor function.  The
    * property value is returned.
    */
   void* UnsetProperty(const nsPropertyOwner& aObject,
-                      nsAtom    *aPropertyName,
-                      nsresult   *aStatus = nullptr)
+                      nsAtom* aPropertyName,
+                      nsresult* aStatus = nullptr)
   {
     return GetPropertyInternal(aObject, aPropertyName, true, aStatus);
   }
 
   /**
    * Deletes all of the properties for object |aObject|, calling the
    * destructor function for each property.
    */
@@ -123,27 +119,25 @@ class nsPropertyTable
 
   /**
    * Transfers all properties for object |aObject| that were set with the
    * |aTransfer| argument as true to |aTable|. Deletes the other properties
    * for object |aObject|, calling the destructor function for each property.
    * If transfering a property fails, this deletes all the properties for
    * object |aObject|.
    */
-  nsresult
-    TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
-                                     nsPropertyTable *aOtherTable);
+  nsresult TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
+                                            nsPropertyTable& aOtherTable);
 
   /**
    * Enumerate the properties for object |aObject|.
    * For every property |aCallback| will be called with as arguments |aObject|,
    * the property name, the property value and |aData|.
    */
-  void Enumerate(nsPropertyOwner aObject,
-                             NSPropertyFunc aCallback, void *aData);
+  void Enumerate(nsPropertyOwner aObject, NSPropertyFunc aCallback, void* aData);
 
   /**
    * Enumerate all the properties.
    * For every property |aCallback| will be called with arguments the owner,
    * the property name, the property value and |aData|.
    */
   void EnumerateAll(NSPropertyFunc aCallback, void *aData);
 
@@ -168,24 +162,23 @@ class nsPropertyTable
 
   class PropertyList;
 
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
  private:
   void DestroyPropertyList();
-  PropertyList* GetPropertyListFor(nsAtom *aPropertyName) const;
+  PropertyList* GetPropertyListFor(nsAtom* aPropertyName) const;
   void* GetPropertyInternal(nsPropertyOwner aObject,
-                                        nsAtom    *aPropertyName,
-                                        bool        aRemove,
-                                        nsresult   *aStatus);
-  nsresult SetPropertyInternal(nsPropertyOwner     aObject,
-                                           nsAtom            *aPropertyName,
-                                           void               *aPropertyValue,
-                                           NSPropertyDtorFunc  aDtor,
-                                           void               *aDtorData,
-                                           bool                aTransfer,
-                                           void              **aOldValue);
+                            nsAtom* aPropertyName,
+                            bool aRemove,
+                            nsresult* aStatus);
+  nsresult SetPropertyInternal(nsPropertyOwner aObject,
+                               nsAtom* aPropertyName,
+                               void* aPropertyValue,
+                               NSPropertyDtorFunc  aDtor,
+                               void* aDtorData,
+                               bool aTransfer);
 
   PropertyList *mPropertyList;
 };
 #endif
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -802,11 +802,10 @@ tags = audiochannel
 [test_window_keys.html]
 [test_window_named_frame_enumeration.html]
 [test_window_orientation.html]
 skip-if = true # bug 1312417
 [test_window_own_props.html]
 [test_window_proto.html]
 [test_writable-replaceable.html]
 [test_x-frame-options.html]
-[test_xbl_userdata.xhtml]
 [test_youtube_flash_embed.html]
 # Please keep alphabetical order.
--- a/dom/base/test/test_bug548463.html
+++ b/dom/base/test/test_bug548463.html
@@ -55,29 +55,12 @@ frag.appendChild(elem1);
 frag.appendChild(elem2);
 testAdoptFromDOMNodeRemoved(frag, elem1, elem2);
 
 content.appendChild(elem1);
 testAdoptFromDOMNodeRemoved(elem1, elem1, content);
 
 content.appendChild(elem1);
 
-var thrown = false;
-
-function changeOwnerDocument()
-{
-  SpecialPowers.wrap(elem1).setUserData("foo", null, null);
-  otherDoc.adoptNode(elem1);
-}
-SpecialPowers.wrap(elem1).setUserData("foo", "bar", changeOwnerDocument);
-try {
-  document.adoptNode(elem1);
-}
-catch (e) {
-  thrown = true;
-}
-
-ok(!thrown, "adoptNode while adopting should not throw");
-
 </script>
 </pre>
 </body>
 </html>
deleted file mode 100644
--- a/dom/base/test/test_xbl_userdata.xhtml
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE HTML>
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>Test for getUserData/setUserData support in XBL</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<style type="text/css">
-#t {
--moz-binding: url(#xbl);
-}
-</style>
-
-<bindings xmlns="http://www.mozilla.org/xbl">
-<binding id="xbl" inheritstyle="false">
-<implementation><constructor><![CDATA[
-  this.textContent = !!(this.getUserData && this.setUserData);
-]]></constructor></implementation>
-</binding>
-</bindings>
-
-</head>
-<body>
-<p id="display"></p>
-
-<pre id="test">
-<script class="testbody">
-<![CDATA[
-"use strict";
-
-var url = '<div id=t style="-moz-binding:url(' + location + '#xbl)"></div>';
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(test1);
-
-function test1() {
-  var iframe = document.createElement('iframe');
-  iframe.srcdoc = url;
-  iframe.onload = function() {
-    var t = iframe.contentWindow.t;
-    is(!!(t.getUserData || t.setUserData), false,
-       "getUserData and setUserData should not be visible from the regular content");
-    is(t.textContent, "true",
-       "getUserData and setUserData should be visible from XBL");
-    document.body.removeChild(iframe);
-    SimpleTest.finish();
-  };
-  document.body.appendChild(iframe);
-}
-
-]]>
-</script>
-</pre>
-</body>
-</html>
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1425,18 +1425,17 @@ nsHTMLDocument::Open(JSContext* cx,
   if (nsPIDOMWindowInner *window = GetInnerWindow()) {
     // Remember the old scope in case the call to SetNewDocument changes it.
     nsCOMPtr<nsIScriptGlobalObject> oldScope(do_QueryReferent(mScopeObject));
 
 #ifdef DEBUG
     bool willReparent = mWillReparent;
     mWillReparent = true;
 
-    nsDocument* templateContentsOwner =
-      static_cast<nsDocument*>(mTemplateContentsOwner.get());
+    nsIDocument* templateContentsOwner = mTemplateContentsOwner.get();
 
     if (templateContentsOwner) {
       templateContentsOwner->mWillReparent = true;
     }
 #endif
 
     // Set our ready state to uninitialized before setting the new document so
     // that window creation listeners don't use the document in its intermediate
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -94,20 +94,16 @@ interface Node : EventTarget {
   [Pure]
   DOMString? lookupPrefix(DOMString? namespace);
   [Pure]
   DOMString? lookupNamespaceURI(DOMString? prefix);
   [Pure]
   boolean isDefaultNamespace(DOMString? namespace);
 
   // Mozilla-specific stuff
-  [Throws, Func="IsChromeOrXBL"]
-  any setUserData(DOMString key, any data);
-  [Throws, Func="IsChromeOrXBL"]
-  any getUserData(DOMString key);
   [ChromeOnly]
   readonly attribute Principal nodePrincipal;
   [ChromeOnly]
   readonly attribute URI? baseURIObject;
   [ChromeOnly]
   sequence<MutationObserver> getBoundMutationObservers();
   [ChromeOnly]
   DOMString generateXPath();
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -1155,16 +1155,51 @@ XULDocument::Persist(const nsAString& aI
         }
 
         nameSpaceID = kNameSpaceID_None;
     }
 
     aRv = Persist(element, nameSpaceID, tag);
 }
 
+enum class ConversionDirection {
+    InnerToOuter,
+    OuterToInner,
+};
+
+static void
+ConvertWindowSize(nsIXULWindow* aWin,
+                  nsAtom* aAttr,
+                  ConversionDirection aDirection,
+                  nsAString& aInOutString)
+{
+    MOZ_ASSERT(aWin);
+    MOZ_ASSERT(aAttr == nsGkAtoms::width || aAttr == nsGkAtoms::height);
+
+    nsresult rv;
+    int32_t size = aInOutString.ToInteger(&rv);
+    if (NS_FAILED(rv)) {
+        return;
+    }
+
+    int32_t sizeDiff = aAttr == nsGkAtoms::width
+        ? aWin->GetOuterToInnerWidthDifferenceInCSSPixels()
+        : aWin->GetOuterToInnerHeightDifferenceInCSSPixels();
+
+    if (!sizeDiff) {
+        return;
+    }
+
+    int32_t multiplier =
+        aDirection == ConversionDirection::InnerToOuter ? 1 : - 1;
+
+    CopyASCIItoUTF16(nsPrintfCString("%d", size + multiplier * sizeDiff),
+                     aInOutString);
+}
+
 nsresult
 XULDocument::Persist(Element* aElement, int32_t aNameSpaceID,
                      nsAtom* aAttribute)
 {
     // For non-chrome documents, persistance is simply broken
     if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()))
         return NS_ERROR_NOT_AVAILABLE;
 
@@ -1193,19 +1228,31 @@ XULDocument::Persist(Element* aElement, 
     bool hasAttr;
     rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr);
     if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
     }
 
     if (hasAttr && valuestr.IsEmpty()) {
         return mLocalStore->RemoveValue(uri, id, attrstr);
-    } else {
-        return mLocalStore->SetValue(uri, id, attrstr, valuestr);
     }
+
+    // Make sure we store the <window> attributes as outer window size, see
+    // bug 1444525 & co.
+    if (aElement->IsXULElement(nsGkAtoms::window) &&
+        (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
+        if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
+            ConvertWindowSize(win,
+                              aAttribute,
+                              ConversionDirection::InnerToOuter,
+                              valuestr);
+        }
+    }
+
+    return mLocalStore->SetValue(uri, id, attrstr, valuestr);
 }
 
 
 nsresult
 XULDocument::GetViewportSize(int32_t* aWidth,
                              int32_t* aHeight)
 {
     *aWidth = *aHeight = 0;
@@ -1743,17 +1790,16 @@ XULDocument::ApplyPersistentAttributesIn
         if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
         }
     }
 
     return NS_OK;
 }
 
-
 nsresult
 XULDocument::ApplyPersistentAttributesToElements(const nsAString &aID,
                                                  nsCOMArray<Element>& aElements)
 {
     nsAutoCString utf8uri;
     nsresult rv = mDocumentURI->GetSpec(utf8uri);
     if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
@@ -1784,23 +1830,39 @@ XULDocument::ApplyPersistentAttributesTo
         }
 
         RefPtr<nsAtom> attr = NS_Atomize(attrstr);
         if (NS_WARN_IF(!attr)) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
 
         uint32_t cnt = aElements.Count();
-
         for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
             RefPtr<Element> element = aElements.SafeObjectAt(i);
             if (!element) {
                  continue;
             }
 
+            // Convert attributes from outer size to inner size for top-level
+            // windows, see bug 1444525 & co.
+            if (element->IsXULElement(nsGkAtoms::window) &&
+                (attr == nsGkAtoms::width || attr == nsGkAtoms::height)) {
+                if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
+                    nsAutoString maybeConvertedValue = value;
+                    ConvertWindowSize(win,
+                                      attr,
+                                      ConversionDirection::OuterToInner,
+                                      maybeConvertedValue);
+                    Unused <<
+                        element->SetAttr(kNameSpaceID_None, attr, maybeConvertedValue, true);
+
+                    continue;
+                }
+            }
+
             Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
         }
     }
 
     return NS_OK;
 }
 
 void
@@ -2625,16 +2687,37 @@ XULDocument::ResumeWalk()
 
     mStillWalking = false;
     if (mPendingSheets == 0) {
         rv = DoneWalking();
     }
     return rv;
 }
 
+already_AddRefed<nsIXULWindow>
+XULDocument::GetXULWindowIfToplevelChrome() const
+{
+    nsCOMPtr<nsIDocShellTreeItem> item = GetDocShell();
+    if (!item) {
+        return nullptr;
+    }
+    nsCOMPtr<nsIDocShellTreeOwner> owner;
+    item->GetTreeOwner(getter_AddRefs(owner));
+    nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(owner);
+    if (!xulWin) {
+        return nullptr;
+    }
+    nsCOMPtr<nsIDocShell> xulWinShell;
+    xulWin->GetDocShell(getter_AddRefs(xulWinShell));
+    if (!SameCOMIdentity(xulWinShell, item)) {
+        return nullptr;
+    }
+    return xulWin.forget();
+}
+
 nsresult
 XULDocument::DoneWalking()
 {
     NS_PRECONDITION(mPendingSheets == 0, "there are sheets to be loaded");
     NS_PRECONDITION(!mStillWalking, "walk not done");
 
     // XXXldb This is where we should really be setting the chromehidden
     // attribute.
@@ -2666,27 +2749,19 @@ XULDocument::DoneWalking()
             static_cast<nsIDocument*>(this),
             NS_LITERAL_STRING("MozBeforeInitialXULLayout"),
             true,
             false);
 
         // Before starting layout, check whether we're a toplevel chrome
         // window.  If we are, setup some state so that we don't have to restyle
         // the whole tree after StartLayout.
-        if (nsCOMPtr<nsIDocShellTreeItem> item = GetDocShell()) {
-            nsCOMPtr<nsIDocShellTreeOwner> owner;
-            item->GetTreeOwner(getter_AddRefs(owner));
-            if (nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(owner)) {
-                nsCOMPtr<nsIDocShell> xulWinShell;
-                xulWin->GetDocShell(getter_AddRefs(xulWinShell));
-                if (SameCOMIdentity(xulWinShell, item)) {
-                    // We're the chrome document!
-                    xulWin->BeforeStartLayout();
-                }
-            }
+        if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
+            // We're the chrome document!
+            win->BeforeStartLayout();
         }
 
         StartLayout();
 
         if (mIsWritingFastLoad && IsChromeURI(mDocumentURI))
             nsXULPrototypeCache::GetInstance()->WritePrototype(mMasterPrototype);
 
         NS_ASSERTION(mDelayFrameLoaderInitialization,
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -194,16 +194,20 @@ public:
                  ErrorResult& aRv);
     using nsDocument::GetBoxObjectFor;
     void LoadOverlay(const nsAString& aURL, nsIObserver* aObserver,
                      ErrorResult& aRv);
 
 protected:
     virtual ~XULDocument();
 
+    // Returns the associated XUL window if this is a top-level chrome document,
+    // null otherwise.
+    already_AddRefed<nsIXULWindow> GetXULWindowIfToplevelChrome() const;
+
     // Implementation methods
     friend nsresult
     (::NS_NewXULDocument(nsIDocument** aResult));
 
     nsresult Init(void) override;
     nsresult StartLayout(void);
 
     nsresult GetViewportSize(int32_t* aWidth, int32_t* aHeight);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6514,17 +6514,17 @@ IonBuilder::jsop_initprop(PropertyName* 
                 if (templateObject->as<PlainObject>().containsPure(name))
                     useFastPath = true;
             } else {
                 MOZ_ASSERT(templateObject->as<UnboxedPlainObject>().layout().lookup(name));
                 useFastPath = true;
             }
         }
     }
-    MInstruction* last = *current->rbegin();
+    MInstructionReverseIterator last = current->rbegin();
 
     if (useFastPath && !forceInlineCaches()) {
         // This is definitely initializing an 'own' property of the object, treat
         // it as an assignment.
         MOZ_TRY(jsop_setprop(name));
     } else {
         MDefinition* value = current->pop();
         MDefinition* obj = current->pop();
@@ -6536,17 +6536,17 @@ IonBuilder::jsop_initprop(PropertyName* 
         MOZ_TRY(setPropTryCache(&emitted, obj, name, value, barrier));
         MOZ_ASSERT(emitted == true);
     }
 
     // SETPROP pushed the value, instead of the object. Fix this on the stack,
     // and check the most recent resume point to see if it needs updating too.
     current->pop();
     current->push(obj);
-    for (MInstructionReverseIterator riter = current->rbegin(); *riter != last; riter++) {
+    for (MInstructionReverseIterator riter = current->rbegin(); riter != last; riter++) {
         if (MResumePoint* resumePoint = riter->resumePoint()) {
             MOZ_ASSERT(resumePoint->pc() == pc);
             if (resumePoint->mode() == MResumePoint::ResumeAfter) {
                 size_t index = resumePoint->numOperands() - 1;
                 resumePoint->replaceOperand(index, obj);
             }
             break;
         }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -5190,16 +5190,71 @@ LIRGenerator::visitGetPrototypeOf(MGetPr
     MOZ_ASSERT(ins->target()->type() == MIRType::Object);
     MOZ_ASSERT(ins->type() == MIRType::Value);
 
     auto lir = new(alloc()) LGetPrototypeOf(useRegister(ins->target()));
     defineBox(lir, ins);
     assignSafepoint(lir, ins);
 }
 
+void
+LIRGenerator::visitConstant(MConstant* ins)
+{
+    if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
+        emitAtUses(ins);
+        return;
+    }
+
+    switch (ins->type()) {
+      case MIRType::Double:
+        define(new(alloc()) LDouble(ins->toDouble()), ins);
+        break;
+      case MIRType::Float32:
+        define(new(alloc()) LFloat32(ins->toFloat32()), ins);
+        break;
+      case MIRType::Boolean:
+        define(new(alloc()) LInteger(ins->toBoolean()), ins);
+        break;
+      case MIRType::Int32:
+        define(new(alloc()) LInteger(ins->toInt32()), ins);
+        break;
+      case MIRType::Int64:
+        defineInt64(new(alloc()) LInteger64(ins->toInt64()), ins);
+        break;
+      case MIRType::String:
+        define(new(alloc()) LPointer(ins->toString()), ins);
+        break;
+      case MIRType::Symbol:
+        define(new(alloc()) LPointer(ins->toSymbol()), ins);
+        break;
+      case MIRType::Object:
+        define(new(alloc()) LPointer(&ins->toObject()), ins);
+        break;
+      default:
+        // Constants of special types (undefined, null) should never flow into
+        // here directly. Operations blindly consuming them require a Box.
+        MOZ_CRASH("unexpected constant type");
+    }
+}
+
+void
+LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant* ins)
+{
+    switch (ins->type()) {
+      case MIRType::Double:
+        define(new(alloc()) LDouble(ins->toDouble()), ins);
+        break;
+      case MIRType::Float32:
+        define(new(alloc()) LFloat32(ins->toFloat32()), ins);
+        break;
+      default:
+        MOZ_CRASH("unexpected constant type");
+    }
+}
+
 #ifdef JS_JITSPEW
 static void
 SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
 {
     Fprinter& out = JitSpewPrinter();
     out.printf("Current resume point %p details:\n", (void*)resumePoint);
     out.printf("    frame count: %u\n", resumePoint->frameCount());
 
@@ -5223,23 +5278,29 @@ SpewResumePoint(MBasicBlock* block, MIns
         out.printf("\n");
     }
 }
 #endif
 
 void
 LIRGenerator::visitInstructionDispatch(MInstruction* ins)
 {
+#ifdef JS_CODEGEN_NONE
+    // Don't compile the switch-statement below so that we don't have to define
+    // the platform-specific visit* methods for the none-backend.
+    MOZ_CRASH();
+#else
     switch (ins->op()) {
-#define MIR_OP(op) case MDefinition::Opcode::op: visit##op(ins->to##op()); break;
+# define MIR_OP(op) case MDefinition::Opcode::op: visit##op(ins->to##op()); break;
     MIR_OPCODE_LIST(MIR_OP)
-#undef MIR_OP
+# undef MIR_OP
       default:
         MOZ_CRASH("Invalid instruction");
     }
+#endif
 }
 
 void
 LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins)
 {
     static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins);
 }
 
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -61,305 +61,23 @@ class LIRGenerator final : public LIRGen
     void lowerBinaryV(JSOp op, MBinaryInstruction* ins);
     void definePhis();
 
     MOZ_MUST_USE bool lowerCallArguments(MCall* call);
 
     template <typename LClass>
     LInstruction* lowerWasmCall(MWasmCall* ins, bool needsBoundsCheck);
 
-  public:
+    friend class LIRGeneratorShared;
     void visitInstructionDispatch(MInstruction* ins);
+
     MOZ_MUST_USE bool visitInstruction(MInstruction* ins);
     MOZ_MUST_USE bool visitBlock(MBasicBlock* block);
 
-    // Visitor hooks are explicit, to give CPU-specific versions a chance to
-    // intercept without a bunch of explicit gunk in the .cpp.
-    void visitCloneLiteral(MCloneLiteral* ins);
-    void visitParameter(MParameter* param);
-    void visitCallee(MCallee* callee);
-    void visitIsConstructing(MIsConstructing* ins);
-    void visitGoto(MGoto* ins);
-    void visitTableSwitch(MTableSwitch* tableswitch);
-    void visitNewArray(MNewArray* ins);
-    void visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins);
-    void visitNewArrayDynamicLength(MNewArrayDynamicLength* ins);
-    void visitNewIterator(MNewIterator* ins);
-    void visitNewTypedArray(MNewTypedArray* ins);
-    void visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins);
-    void visitNewObject(MNewObject* ins);
-    void visitNewTypedObject(MNewTypedObject* ins);
-    void visitNewNamedLambdaObject(MNewNamedLambdaObject* ins);
-    void visitNewCallObject(MNewCallObject* ins);
-    void visitNewSingletonCallObject(MNewSingletonCallObject* ins);
-    void visitNewStringObject(MNewStringObject* ins);
-    void visitNewDerivedTypedObject(MNewDerivedTypedObject* ins);
-    void visitInitElem(MInitElem* ins);
-    void visitInitElemGetterSetter(MInitElemGetterSetter* ins);
-    void visitMutateProto(MMutateProto* ins);
-    void visitInitPropGetterSetter(MInitPropGetterSetter* ins);
-    void visitCheckOverRecursed(MCheckOverRecursed* ins);
-    void visitDefVar(MDefVar* ins);
-    void visitDefLexical(MDefLexical* ins);
-    void visitDefFun(MDefFun* ins);
-    void visitCreateThisWithTemplate(MCreateThisWithTemplate* ins);
-    void visitCreateThisWithProto(MCreateThisWithProto* ins);
-    void visitCreateThis(MCreateThis* ins);
-    void visitCreateArgumentsObject(MCreateArgumentsObject* ins);
-    void visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins);
-    void visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins);
-    void visitReturnFromCtor(MReturnFromCtor* ins);
-    void visitComputeThis(MComputeThis* ins);
-    void visitImplicitThis(MImplicitThis* ins);
-    void visitCall(MCall* call);
-    void visitApplyArgs(MApplyArgs* apply);
-    void visitApplyArray(MApplyArray* apply);
-    void visitBail(MBail* bail);
-    void visitUnreachable(MUnreachable* unreachable);
-    void visitEncodeSnapshot(MEncodeSnapshot* ins);
-    void visitAssertFloat32(MAssertFloat32* ins);
-    void visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* ins);
-    void visitGetDynamicName(MGetDynamicName* ins);
-    void visitCallDirectEval(MCallDirectEval* ins);
-    void visitTest(MTest* test);
-    void visitGotoWithFake(MGotoWithFake* ins);
-    void visitFunctionDispatch(MFunctionDispatch* ins);
-    void visitObjectGroupDispatch(MObjectGroupDispatch* ins);
-    void visitCompare(MCompare* comp);
-    void visitSameValue(MSameValue* comp);
-    void visitTypeOf(MTypeOf* ins);
-    void visitToAsync(MToAsync* ins);
-    void visitToAsyncGen(MToAsyncGen* ins);
-    void visitToAsyncIter(MToAsyncIter* ins);
-    void visitToId(MToId* ins);
-    void visitBitNot(MBitNot* ins);
-    void visitBitAnd(MBitAnd* ins);
-    void visitBitOr(MBitOr* ins);
-    void visitBitXor(MBitXor* ins);
-    void visitLsh(MLsh* ins);
-    void visitRsh(MRsh* ins);
-    void visitUrsh(MUrsh* ins);
-    void visitSignExtendInt32(MSignExtendInt32* ins);
-    void visitRotate(MRotate* ins);
-    void visitFloor(MFloor* ins);
-    void visitCeil(MCeil* ins);
-    void visitRound(MRound* ins);
-    void visitNearbyInt(MNearbyInt* ins);
-    void visitMinMax(MMinMax* ins);
-    void visitAbs(MAbs* ins);
-    void visitClz(MClz* ins);
-    void visitCtz(MCtz* ins);
-    void visitSqrt(MSqrt* ins);
-    void visitPopcnt(MPopcnt* ins);
-    void visitAtan2(MAtan2* ins);
-    void visitHypot(MHypot* ins);
-    void visitPow(MPow* ins);
-    void visitMathFunction(MMathFunction* ins);
-    void visitAdd(MAdd* ins);
-    void visitSub(MSub* ins);
-    void visitMul(MMul* ins);
-    void visitDiv(MDiv* ins);
-    void visitMod(MMod* ins);
-    void visitConcat(MConcat* ins);
-    void visitCharCodeAt(MCharCodeAt* ins);
-    void visitFromCharCode(MFromCharCode* ins);
-    void visitFromCodePoint(MFromCodePoint* ins);
-    void visitStringConvertCase(MStringConvertCase* ins);
-    void visitSinCos(MSinCos *ins);
-    void visitStringSplit(MStringSplit* ins);
-    void visitStart(MStart* start);
-    void visitOsrEntry(MOsrEntry* entry);
-    void visitNop(MNop* nop);
-    void visitLimitedTruncate(MLimitedTruncate* nop);
-    void visitOsrValue(MOsrValue* value);
-    void visitOsrEnvironmentChain(MOsrEnvironmentChain* object);
-    void visitOsrReturnValue(MOsrReturnValue* value);
-    void visitOsrArgumentsObject(MOsrArgumentsObject* object);
-    void visitToDouble(MToDouble* convert);
-    void visitToFloat32(MToFloat32* convert);
-    void visitToNumberInt32(MToNumberInt32* convert);
-    void visitTruncateToInt32(MTruncateToInt32* truncate);
-    void visitWasmTruncateToInt32(MWasmTruncateToInt32* truncate);
-    void visitWrapInt64ToInt32(MWrapInt64ToInt32* ins);
-    void visitToString(MToString* convert);
-    void visitToObject(MToObject* convert);
-    void visitToObjectOrNull(MToObjectOrNull* convert);
-    void visitRegExp(MRegExp* ins);
-    void visitRegExpMatcher(MRegExpMatcher* ins);
-    void visitRegExpSearcher(MRegExpSearcher* ins);
-    void visitRegExpTester(MRegExpTester* ins);
-    void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins);
-    void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins);
-    void visitGetFirstDollarIndex(MGetFirstDollarIndex* ins);
-    void visitStringReplace(MStringReplace* ins);
-    void visitBinarySharedStub(MBinarySharedStub* ins);
-    void visitUnarySharedStub(MUnarySharedStub* ins);
-    void visitNullarySharedStub(MNullarySharedStub* ins);
-    void visitClassConstructor(MClassConstructor* ins);
-    void visitLambda(MLambda* ins);
-    void visitLambdaArrow(MLambdaArrow* ins);
-    void visitSetFunName(MSetFunName* ins);
-    void visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* ins);
-    void visitCopyLexicalEnvironmentObject(MCopyLexicalEnvironmentObject* ins);
-    void visitKeepAliveObject(MKeepAliveObject* ins);
-    void visitSlots(MSlots* ins);
-    void visitElements(MElements* ins);
-    void visitConstantElements(MConstantElements* ins);
-    void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins);
-    void visitMaybeToDoubleElement(MMaybeToDoubleElement* ins);
-    void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins);
-    void visitLoadSlot(MLoadSlot* ins);
-    void visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins);
-    void visitFunctionEnvironment(MFunctionEnvironment* ins);
-    void visitHomeObject(MHomeObject* ins);
-    void visitHomeObjectSuperBase(MHomeObjectSuperBase* ins);
-    void visitInterruptCheck(MInterruptCheck* ins);
-    void visitWasmInterruptCheck(MWasmInterruptCheck* ins);
-    void visitWasmTrap(MWasmTrap* ins);
-    void visitWasmReinterpret(MWasmReinterpret* ins);
-    void visitStoreSlot(MStoreSlot* ins);
-    void visitFilterTypeSet(MFilterTypeSet* ins);
-    void visitTypeBarrier(MTypeBarrier* ins);
-    void visitPostWriteBarrier(MPostWriteBarrier* ins);
-    void visitPostWriteElementBarrier(MPostWriteElementBarrier* ins);
-    void visitArrayLength(MArrayLength* ins);
-    void visitSetArrayLength(MSetArrayLength* ins);
-    void visitGetNextEntryForIterator(MGetNextEntryForIterator* ins);
-    void visitTypedArrayLength(MTypedArrayLength* ins);
-    void visitTypedArrayElements(MTypedArrayElements* ins);
-    void visitSetDisjointTypedElements(MSetDisjointTypedElements* ins);
-    void visitTypedObjectElements(MTypedObjectElements* ins);
-    void visitSetTypedObjectOffset(MSetTypedObjectOffset* ins);
-    void visitTypedObjectDescr(MTypedObjectDescr* ins);
-    void visitInitializedLength(MInitializedLength* ins);
-    void visitSetInitializedLength(MSetInitializedLength* ins);
-    void visitNot(MNot* ins);
-    void visitBoundsCheck(MBoundsCheck* ins);
-    void visitBoundsCheckLower(MBoundsCheckLower* ins);
-    void visitSpectreMaskIndex(MSpectreMaskIndex* ins);
-    void visitLoadElement(MLoadElement* ins);
-    void visitLoadElementHole(MLoadElementHole* ins);
-    void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins);
-    void visitLoadUnboxedString(MLoadUnboxedString* ins);
-    void visitLoadElementFromState(MLoadElementFromState* ins);
-    void visitStoreElement(MStoreElement* ins);
-    void visitStoreElementHole(MStoreElementHole* ins);
-    void visitFallibleStoreElement(MFallibleStoreElement* ins);
-    void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
-    void visitStoreUnboxedString(MStoreUnboxedString* ins);
-    void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins);
-    void visitEffectiveAddress(MEffectiveAddress* ins);
-    void visitArrayPopShift(MArrayPopShift* ins);
-    void visitArrayPush(MArrayPush* ins);
-    void visitArraySlice(MArraySlice* ins);
-    void visitArrayJoin(MArrayJoin* ins);
-    void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins);
-    void visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole* ins);
-    void visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic* ins);
-    void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins);
-    void visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins);
-    void visitClampToUint8(MClampToUint8* ins);
-    void visitLoadFixedSlot(MLoadFixedSlot* ins);
-    void visitStoreFixedSlot(MStoreFixedSlot* ins);
-    void visitGetPropSuperCache(MGetPropSuperCache* ins);
-    void visitGetPropertyCache(MGetPropertyCache* ins);
-    void visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins);
-    void visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins);
-    void visitBindNameCache(MBindNameCache* ins);
-    void visitCallBindVar(MCallBindVar* ins);
-    void visitGuardObjectIdentity(MGuardObjectIdentity* ins);
-    void visitGuardShape(MGuardShape* ins);
-    void visitGuardObjectGroup(MGuardObjectGroup* ins);
-    void visitGuardObject(MGuardObject* ins);
-    void visitGuardString(MGuardString* ins);
-    void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins);
-    void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins);
-    void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins);
-    void visitPolyInlineGuard(MPolyInlineGuard* ins);
-    void visitAssertRange(MAssertRange* ins);
-    void visitCallGetProperty(MCallGetProperty* ins);
-    void visitDeleteProperty(MDeleteProperty* ins);
-    void visitDeleteElement(MDeleteElement* ins);
-    void visitGetNameCache(MGetNameCache* ins);
-    void visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins);
-    void visitCallGetElement(MCallGetElement* ins);
-    void visitCallSetElement(MCallSetElement* ins);
-    void visitCallInitElementArray(MCallInitElementArray* ins);
-    void visitSetPropertyCache(MSetPropertyCache* ins);
-    void visitCallSetProperty(MCallSetProperty* ins);
-    void visitGetIteratorCache(MGetIteratorCache* ins);
-    void visitIteratorMore(MIteratorMore* ins);
-    void visitIsNoIter(MIsNoIter* ins);
-    void visitIteratorEnd(MIteratorEnd* ins);
-    void visitStringLength(MStringLength* ins);
-    void visitArgumentsLength(MArgumentsLength* ins);
-    void visitGetFrameArgument(MGetFrameArgument* ins);
-    void visitSetFrameArgument(MSetFrameArgument* ins);
-    void visitRunOncePrologue(MRunOncePrologue* ins);
-    void visitRest(MRest* ins);
-    void visitThrow(MThrow* ins);
-    void visitInCache(MInCache* ins);
-    void visitInArray(MInArray* ins);
-    void visitHasOwnCache(MHasOwnCache* ins);
-    void visitInstanceOf(MInstanceOf* ins);
-    void visitInstanceOfCache(MInstanceOfCache* ins);
-    void visitIsCallable(MIsCallable* ins);
-    void visitIsConstructor(MIsConstructor* ins);
-    void visitIsArray(MIsArray* ins);
-    void visitIsTypedArray(MIsTypedArray* ins);
-    void visitIsObject(MIsObject* ins);
-    void visitHasClass(MHasClass* ins);
-    void visitObjectClassToString(MObjectClassToString* ins);
-    void visitWasmAddOffset(MWasmAddOffset* ins);
-    void visitWasmLoadTls(MWasmLoadTls* ins);
-    void visitWasmBoundsCheck(MWasmBoundsCheck* ins);
-    void visitWasmAlignmentCheck(MWasmAlignmentCheck* ins);
-    void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins);
-    void visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins);
-    void visitWasmParameter(MWasmParameter* ins);
-    void visitWasmReturn(MWasmReturn* ins);
-    void visitWasmReturnVoid(MWasmReturnVoid* ins);
-    void visitWasmStackArg(MWasmStackArg* ins);
-    void visitWasmCall(MWasmCall* ins);
-    void visitSetDOMProperty(MSetDOMProperty* ins);
-    void visitGetDOMProperty(MGetDOMProperty* ins);
-    void visitGetDOMMember(MGetDOMMember* ins);
-    void visitRecompileCheck(MRecompileCheck* ins);
-    void visitSimdBox(MSimdBox* ins);
-    void visitSimdUnbox(MSimdUnbox* ins);
-    void visitSimdUnaryArith(MSimdUnaryArith* ins);
-    void visitSimdBinaryComp(MSimdBinaryComp* ins);
-    void visitSimdBinaryBitwise(MSimdBinaryBitwise* ins);
-    void visitSimdShift(MSimdShift* ins);
-    void visitSimdConstant(MSimdConstant* ins);
-    void visitSimdConvert(MSimdConvert* ins);
-    void visitSimdReinterpretCast(MSimdReinterpretCast* ins);
-    void visitSimdAllTrue(MSimdAllTrue* ins);
-    void visitSimdAnyTrue(MSimdAnyTrue* ins);
-    void visitPhi(MPhi* ins);
-    void visitBeta(MBeta* ins);
-    void visitObjectState(MObjectState* ins);
-    void visitArrayState(MArrayState* ins);
-    void visitArgumentState(MArgumentState* ins);
-    void visitUnknownValue(MUnknownValue* ins);
-    void visitLexicalCheck(MLexicalCheck* ins);
-    void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins);
-    void visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins);
-    void visitDebugger(MDebugger* ins);
-    void visitNewTarget(MNewTarget* ins);
-    void visitArrowNewTarget(MArrowNewTarget* ins);
-    void visitNaNToZero(MNaNToZero *ins);
-    void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
-    void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
-    void visitCheckReturn(MCheckReturn* ins);
-    void visitCheckIsObj(MCheckIsObj* ins);
-    void visitCheckIsCallable(MCheckIsCallable* ins);
-    void visitCheckObjCoercible(MCheckObjCoercible* ins);
-    void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins);
-    void visitFinishBoundFunctionInit(MFinishBoundFunctionInit* ins);
-    void visitIsPackedArray(MIsPackedArray* ins);
-    void visitGetPrototypeOf(MGetPrototypeOf* ins);
+#define MIR_OP(op) void visit##op(M##op* ins);
+    MIR_OPCODE_LIST(MIR_OP)
+#undef MIR_OP
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Lowering_h */
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -1,20 +1,21 @@
 /* -*- 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 "jit/arm/Lowering-arm.h"
+
 #include "mozilla/MathAlgorithms.h"
 
 #include "jit/arm/Assembler-arm.h"
 #include "jit/Lowering.h"
 #include "jit/MIR.h"
-
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::FloorLog2;
 
 LBoxAllocation
@@ -48,17 +49,17 @@ LIRGeneratorARM::useByteOpRegisterOrNonD
 
 LDefinition
 LIRGeneratorARM::tempByteOpRegister()
 {
     return temp();
 }
 
 void
-LIRGeneratorARM::visitBox(MBox* box)
+LIRGenerator::visitBox(MBox* box)
 {
     MDefinition* inner = box->getOperand(0);
 
     // If the box wrapped a double, it needs a new register.
     if (IsFloatingPointType(inner->type())) {
         defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0),
                                                  inner->type()), box);
         return;
@@ -88,17 +89,17 @@ LIRGeneratorARM::visitBox(MBox* box)
     // ignored.
     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
     lir->setDef(1, LDefinition::BogusTemp());
     box->setVirtualRegister(vreg);
     add(lir);
 }
 
 void
-LIRGeneratorARM::visitUnbox(MUnbox* unbox)
+LIRGenerator::visitUnbox(MUnbox* unbox)
 {
     MDefinition* inner = unbox->getOperand(0);
 
     if (inner->type() == MIRType::ObjectOrNull) {
         LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
         if (unbox->fallible())
             assignSnapshot(lir, unbox->bailoutKind());
         defineReuseInput(lir, unbox, 0);
@@ -132,17 +133,17 @@ LIRGeneratorARM::visitUnbox(MUnbox* unbo
     // before the payload, it could be used as a Value without the type being
     // recoverable. Unbox's purpose is to eagerly kill the definition of a type
     // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
     // Instead, we create a new virtual register.
     defineReuseInput(lir, unbox, 0);
 }
 
 void
-LIRGeneratorARM::visitReturn(MReturn* ret)
+LIRGenerator::visitReturn(MReturn* ret)
 {
     MDefinition* opd = ret->getOperand(0);
     MOZ_ASSERT(opd->type() == MIRType::Value);
 
     LReturn* ins = new(alloc()) LReturn;
     ins->setOperand(0, LUse(JSReturnReg_Type));
     ins->setOperand(1, LUse(JSReturnReg_Data));
     fillBoxUses(ins, 0, opd);
@@ -453,17 +454,17 @@ void
 LIRGeneratorARM::lowerUModI64(MMod* mod)
 {
     LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
                                                     useInt64RegisterAtStart(mod->rhs()));
     defineReturn(lir, mod);
 }
 
 void
-LIRGeneratorARM::visitPowHalf(MPowHalf* ins)
+LIRGenerator::visitPowHalf(MPowHalf* ins)
 {
     MDefinition* input = ins->input();
     MOZ_ASSERT(input->type() == MIRType::Double);
     LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
     defineReuseInput(lir, ins, 0);
 }
 
 LTableSwitch*
@@ -489,17 +490,17 @@ LIRGeneratorARM::lowerUrshD(MUrsh* mir)
     MOZ_ASSERT(lhs->type() == MIRType::Int32);
     MOZ_ASSERT(rhs->type() == MIRType::Int32);
 
     LUrshD* lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
     define(lir, mir);
 }
 
 void
-LIRGeneratorARM::visitWasmSelect(MWasmSelect* ins)
+LIRGenerator::visitWasmSelect(MWasmSelect* ins)
 {
     if (ins->type() == MIRType::Int64) {
         auto* lir = new(alloc()) LWasmSelectI64(useInt64RegisterAtStart(ins->trueExpr()),
                                                 useInt64(ins->falseExpr()),
                                                 useRegister(ins->condExpr()));
 
         defineInt64ReuseInput(lir, ins, LWasmSelectI64::TrueExprIndex);
         return;
@@ -508,17 +509,17 @@ LIRGeneratorARM::visitWasmSelect(MWasmSe
     auto* lir = new(alloc()) LWasmSelect(useRegisterAtStart(ins->trueExpr()),
                                          useRegister(ins->falseExpr()),
                                          useRegister(ins->condExpr()));
 
     defineReuseInput(lir, ins, LWasmSelect::TrueExprIndex);
 }
 
 void
-LIRGeneratorARM::visitWasmNeg(MWasmNeg* ins)
+LIRGenerator::visitWasmNeg(MWasmNeg* ins)
 {
     if (ins->type() == MIRType::Int32) {
         define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
     } else if (ins->type() == MIRType::Float32) {
         define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
     } else {
         MOZ_ASSERT(ins->type() == MIRType::Double);
         define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
@@ -571,33 +572,33 @@ LIRGeneratorARM::lowerUMod(MMod* mod)
 
     if (mod->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
 
     defineReturn(lir, mod);
 }
 
 void
-LIRGeneratorARM::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
+LIRGenerator::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToDouble* lir = new(alloc()) LWasmUint32ToDouble(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
+LIRGenerator::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToFloat32* lir = new(alloc()) LWasmUint32ToFloat32(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitWasmLoad(MWasmLoad* ins)
+LIRGenerator::visitWasmLoad(MWasmLoad* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     if (ins->access().type() == Scalar::Int64 && ins->access().isAtomic()) {
         auto* lir = new(alloc()) LWasmAtomicLoadI64(useRegisterAtStart(base));
         defineInt64Fixed(lir, ins, LInt64Allocation(LAllocation(AnyRegister(IntArgReg1)),
                                                     LAllocation(AnyRegister(IntArgReg0))));
@@ -645,17 +646,17 @@ LIRGeneratorARM::visitWasmLoad(MWasmLoad
     auto* lir = new(alloc()) LWasmLoad(ptr);
     if (ins->access().offset())
         lir->setTemp(0, tempCopy(base, 0));
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitWasmStore(MWasmStore* ins)
+LIRGenerator::visitWasmStore(MWasmStore* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     if (ins->access().type() == Scalar::Int64 && ins->access().isAtomic()) {
         auto* lir = new(alloc()) LWasmAtomicStoreI64(useRegister(base),
                                                      useInt64Fixed(ins->value(),
                                                                    Register64(IntArgReg1,
@@ -706,17 +707,17 @@ LIRGeneratorARM::visitWasmStore(MWasmSto
 
     if (ins->access().offset())
         lir->setTemp(0, tempCopy(base, 0));
 
     add(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
+LIRGenerator::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
 {
     MOZ_ASSERT(ins->offset() == 0);
 
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     // For the ARM it is best to keep the 'base' in a register if a bounds check is needed.
     LAllocation baseAlloc;
@@ -734,17 +735,17 @@ LIRGeneratorARM::visitAsmJSLoadHeap(MAsm
             limitAlloc = useRegisterAtStart(boundsCheckLimit);
         }
     }
 
     define(new(alloc()) LAsmJSLoadHeap(baseAlloc, limitAlloc), ins);
 }
 
 void
-LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
+LIRGenerator::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
 {
     MOZ_ASSERT(ins->offset() == 0);
 
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     LAllocation baseAlloc;
     LAllocation limitAlloc;
@@ -779,23 +780,23 @@ LIRGeneratorARM::lowerTruncateFToInt32(M
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Float32);
 
     define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
 }
 
 void
-LIRGeneratorARM::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
+LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
+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);
 
     const LUse elements = useRegister(ins->elements());
@@ -813,17 +814,17 @@ LIRGeneratorARM::visitAtomicExchangeType
 
     LAtomicExchangeTypedArrayElement* lir =
         new(alloc()) LAtomicExchangeTypedArrayElement(elements, index, value, tempDef);
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
+LIRGenerator::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     MOZ_ASSERT(ins->arrayType() != Scalar::Uint8Clamped);
     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);
 
@@ -855,17 +856,17 @@ LIRGeneratorARM::visitAtomicTypedArrayEl
     // On arm, map flagTemp to temp1 and outTemp to temp2, at least for now.
 
     LAtomicTypedArrayElementBinop* lir =
         new(alloc()) LAtomicTypedArrayElementBinop(elements, index, value, flagTemp, outTemp);
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
+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);
 
     const LUse elements = useRegister(ins->elements());
@@ -886,17 +887,17 @@ LIRGeneratorARM::visitCompareExchangeTyp
 
     LCompareExchangeTypedArrayElement* lir =
         new(alloc()) LCompareExchangeTypedArrayElement(elements, index, oldval, newval, tempDef);
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
+LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     if (ins->access().type() == Scalar::Int64) {
         auto* lir = new(alloc()) LWasmCompareExchangeI64(useRegister(base),
                                                          useInt64Register(ins->oldValue()),
                                                          useInt64Fixed(ins->newValue(),
@@ -914,17 +915,17 @@ LIRGeneratorARM::visitWasmCompareExchang
         new(alloc()) LWasmCompareExchangeHeap(useRegister(base),
                                               useRegister(ins->oldValue()),
                                               useRegister(ins->newValue()));
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
+LIRGenerator::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
 {
     MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
 
     if (ins->access().type() == Scalar::Int64) {
         auto* lir = new(alloc()) LWasmAtomicExchangeI64(useRegister(ins->base()),
                                                         useInt64Fixed(ins->value(),
                                                                       Register64(IntArgReg3,
                                                                                  IntArgReg2)),
@@ -938,17 +939,17 @@ LIRGeneratorARM::visitWasmAtomicExchange
     MOZ_ASSERT(HasLDSTREXBHD(), "by HasCompilerSupport() constraints");
 
     const LAllocation base = useRegister(ins->base());
     const LAllocation value = useRegister(ins->value());
     define(new(alloc()) LWasmAtomicExchangeHeap(base, value), ins);
 }
 
 void
-LIRGeneratorARM::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
+LIRGenerator::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
 {
     if (ins->access().type() == Scalar::Int64) {
         auto* lir = new(alloc()) LWasmAtomicBinopI64(useRegister(ins->base()),
                                                      useInt64Register(ins->value()),
                                                      tempFixed(IntArgReg2),
                                                      tempFixed(IntArgReg3),
                                                      ins->access(),
                                                      ins->operation());
@@ -976,60 +977,60 @@ LIRGeneratorARM::visitWasmAtomicBinopHea
         new(alloc()) LWasmAtomicBinopHeap(useRegister(base),
                                           useRegister(ins->value()),
                                           /* temp = */ LDefinition::BogusTemp(),
                                           /* flagTemp= */ temp());
     define(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitSubstr(MSubstr* ins)
+LIRGenerator::visitSubstr(MSubstr* ins)
 {
     LSubstr* lir = new (alloc()) LSubstr(useRegister(ins->string()),
                                          useRegister(ins->begin()),
                                          useRegister(ins->length()),
                                          temp(),
                                          temp(),
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitRandom(MRandom* ins)
+LIRGenerator::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(),
                                         temp(),
                                         temp(),
                                         temp(),
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
-LIRGeneratorARM::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
+LIRGenerator::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
 
     defineReturn(new(alloc()) LWasmTruncateToInt64(useRegisterAtStart(opd)), ins);
 }
 
 void
-LIRGeneratorARM::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+LIRGenerator::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MOZ_ASSERT(ins->type() == MIRType::Double || ins->type() == MIRType::Float32);
 
     auto* lir = new(alloc()) LInt64ToFloatingPointCall();
     lir->setInt64Operand(0, useInt64RegisterAtStart(ins->input()));
     defineReturn(lir, ins);
 }
 
 void
-LIRGeneratorARM::visitCopySign(MCopySign* ins)
+LIRGenerator::visitCopySign(MCopySign* ins)
 {
     MDefinition* lhs = ins->lhs();
     MDefinition* rhs = ins->rhs();
 
     MOZ_ASSERT(IsFloatingPointType(lhs->type()));
     MOZ_ASSERT(lhs->type() == rhs->type());
     MOZ_ASSERT(lhs->type() == ins->type());
 
@@ -1041,25 +1042,85 @@ LIRGeneratorARM::visitCopySign(MCopySign
 
     lir->setTemp(0, temp());
     lir->setTemp(1, temp());
 
     lowerForFPU(lir, ins, lhs, rhs);
 }
 
 void
-LIRGeneratorARM::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
+LIRGenerator::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     auto* lir = new(alloc()) LExtendInt32ToInt64(useRegisterAtStart(ins->input()));
     defineInt64(lir, ins);
 
     LDefinition def(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT);
     def.setReusedInput(0);
     def.setVirtualRegister(ins->virtualRegister());
 
     lir->setDef(0, def);
 }
 
 void
-LIRGeneratorARM::visitSignExtendInt64(MSignExtendInt64* ins)
+LIRGenerator::visitSignExtendInt64(MSignExtendInt64* ins)
 {
     defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins);
 }
+
+void
+LIRGenerator::visitSimdInsertElement(MSimdInsertElement*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdExtractElement(MSimdExtractElement*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdBinaryArith(MSimdBinaryArith*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSelect(MSimdSelect*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSplat(MSimdSplat*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdValueX4(MSimdValueX4*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdBinarySaturating(MSimdBinarySaturating*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSwizzle(MSimdSwizzle*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdShuffle(MSimdShuffle*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdGeneralShuffle(MSimdGeneralShuffle*)
+{
+    MOZ_CRASH("NYI");
+}
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -9,22 +9,21 @@
 
 #include "jit/shared/Lowering-shared.h"
 
 namespace js {
 namespace jit {
 
 class LIRGeneratorARM : public LIRGeneratorShared
 {
-  public:
+  protected:
     LIRGeneratorARM(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     { }
 
-  protected:
     // Returns a box allocation with type set to reg1 and payload set to reg2.
     LBoxAllocation useBoxFixed(MDefinition* mir, Register reg1, Register reg2,
                                bool useAtStart = false);
 
     // x86 has constraints on what registers can be formatted for 1-byte
     // stores and loads; on ARM all registers are okay.
     LAllocation useByteOpRegister(MDefinition* mir);
     LAllocation useByteOpRegisterAtStart(MDefinition* mir);
@@ -83,49 +82,22 @@ class LIRGeneratorARM : public LIRGenera
     void lowerModI(MMod* mod);
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
-    void visitPowHalf(MPowHalf* ins);
-    void visitWasmNeg(MWasmNeg* ins);
 
     LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
                                   MTableSwitch* ins);
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
 
-  public:
-    void visitBox(MBox* box);
-    void visitUnbox(MUnbox* unbox);
-    void visitReturn(MReturn* ret);
     void lowerPhi(MPhi* phi);
-    void visitWasmSelect(MWasmSelect* ins);
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
-    void visitWasmLoad(MWasmLoad* ins);
-    void visitWasmStore(MWasmStore* ins);
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
-    void visitSubstr(MSubstr* ins);
-    void visitRandom(MRandom* ins);
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
-    void visitCopySign(MCopySign* ins);
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
-    void visitSignExtendInt64(MSignExtendInt64* ins);
 };
 
 typedef LIRGeneratorARM LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm_Lowering_arm_h */
--- a/js/src/jit/arm64/Lowering-arm64.cpp
+++ b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -1,20 +1,19 @@
 /* -*- 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/MathAlgorithms.h"
+#include "jit/arm64/Lowering-arm64.h"
 
 #include "jit/arm64/Assembler-arm64.h"
 #include "jit/Lowering.h"
 #include "jit/MIR.h"
-
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::FloorLog2;
 
 LBoxAllocation
@@ -37,29 +36,29 @@ LIRGeneratorARM64::useByteOpRegisterAtSt
 
 LAllocation
 LIRGeneratorARM64::useByteOpRegisterOrNonDoubleConstant(MDefinition* mir)
 {
     MOZ_CRASH("useByteOpRegisterOrNonDoubleConstant");
 }
 
 void
-LIRGeneratorARM64::visitBox(MBox* box)
+LIRGenerator::visitBox(MBox* box)
 {
     MOZ_CRASH("visitBox");
 }
 
 void
-LIRGeneratorARM64::visitUnbox(MUnbox* unbox)
+LIRGenerator::visitUnbox(MUnbox* unbox)
 {
     MOZ_CRASH("visitUnbox");
 }
 
 void
-LIRGeneratorARM64::visitReturn(MReturn* ret)
+LIRGenerator::visitReturn(MReturn* ret)
 {
     MOZ_CRASH("visitReturn");
 }
 
 // x = !y
 void
 LIRGeneratorARM64::lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input)
 {
@@ -174,17 +173,17 @@ LIRGeneratorARM64::lowerDivI64(MDiv* div
 
 void
 LIRGeneratorARM64::lowerModI64(MMod* mod)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitPowHalf(MPowHalf* ins)
+LIRGenerator::visitPowHalf(MPowHalf* ins)
 {
     MOZ_CRASH("visitPowHalf");
 }
 
 LTableSwitch*
 LIRGeneratorARM64::newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
                                        MTableSwitch* tableswitch)
 {
@@ -199,23 +198,23 @@ LIRGeneratorARM64::newLTableSwitchV(MTab
 
 void
 LIRGeneratorARM64::lowerUrshD(MUrsh* mir)
 {
     MOZ_CRASH("lowerUrshD");
 }
 
 void
-LIRGeneratorARM64::visitWasmNeg(MWasmNeg* ins)
+LIRGenerator::visitWasmNeg(MWasmNeg* ins)
 {
     MOZ_CRASH("visitWasmNeg");
 }
 
 void
-LIRGeneratorARM64::visitWasmSelect(MWasmSelect* ins)
+LIRGenerator::visitWasmSelect(MWasmSelect* ins)
 {
     MOZ_CRASH("visitWasmSelect");
 }
 
 void
 LIRGeneratorARM64::lowerUDiv(MDiv* div)
 {
     MOZ_CRASH("lowerUDiv");
@@ -223,53 +222,53 @@ LIRGeneratorARM64::lowerUDiv(MDiv* div)
 
 void
 LIRGeneratorARM64::lowerUMod(MMod* mod)
 {
     MOZ_CRASH("lowerUMod");
 }
 
 void
-LIRGeneratorARM64::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
+LIRGenerator::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
 {
     MOZ_CRASH("visitWasmUnsignedToDouble");
 }
 
 void
-LIRGeneratorARM64::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
+LIRGenerator::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
 {
     MOZ_CRASH("visitWasmUnsignedToFloat32");
 }
 
 void
-LIRGeneratorARM64::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
+LIRGenerator::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
 {
     MOZ_CRASH("visitAsmJSLoadHeap");
 }
 
 void
-LIRGeneratorARM64::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
+LIRGenerator::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
 {
     MOZ_CRASH("visitAsmJSStoreHeap");
 }
 
 void
-LIRGeneratorARM64::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
+LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
 {
     MOZ_CRASH("visitWasmCompareExchangeHeap");
 }
 
 void
-LIRGeneratorARM64::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
+LIRGenerator::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
 {
     MOZ_CRASH("visitWasmAtomicExchangeHeap");
 }
 
 void
-LIRGeneratorARM64::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
+LIRGenerator::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
 {
     MOZ_CRASH("visitWasmAtomicBinopHeap");
 }
 
 void
 LIRGeneratorARM64::lowerTruncateDToInt32(MTruncateToInt32* ins)
 {
     MOZ_CRASH("lowerTruncateDToInt32");
@@ -277,87 +276,147 @@ LIRGeneratorARM64::lowerTruncateDToInt32
 
 void
 LIRGeneratorARM64::lowerTruncateFToInt32(MTruncateToInt32* ins)
 {
     MOZ_CRASH("lowerTruncateFToInt32");
 }
 
 void
-LIRGeneratorARM64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
+LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
+LIRGenerator::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
+LIRGenerator::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
+LIRGenerator::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitSubstr(MSubstr* ins)
+LIRGenerator::visitSubstr(MSubstr* ins)
 {
     MOZ_CRASH("visitSubstr");
 }
 
 void
-LIRGeneratorARM64::visitRandom(MRandom* ins)
+LIRGenerator::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(),
                                         temp(),
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
-LIRGeneratorARM64::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
+LIRGenerator::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
-    MOZ_CRASH("NY");
+    MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitWasmLoad(MWasmLoad* ins)
+LIRGenerator::visitWasmLoad(MWasmLoad* ins)
 {
-    MOZ_CRASH("NY");
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitWasmStore(MWasmStore* ins)
+{
+    MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitWasmStore(MWasmStore* ins)
+LIRGenerator::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
-    MOZ_CRASH("NY");
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitCopySign(MCopySign* ins)
+{
+    MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+LIRGenerator::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
-    MOZ_CRASH("NY");
+    MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitCopySign(MCopySign* ins)
+LIRGenerator::visitSignExtendInt64(MSignExtendInt64* ins)
 {
-    MOZ_CRASH("NY");
+    MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
+LIRGenerator::visitSimdInsertElement(MSimdInsertElement*)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorARM64::visitSignExtendInt64(MSignExtendInt64* ins)
+LIRGenerator::visitSimdExtractElement(MSimdExtractElement*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdBinaryArith(MSimdBinaryArith*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSelect(MSimdSelect*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSplat(MSimdSplat*)
 {
     MOZ_CRASH("NYI");
 }
+
+void
+LIRGenerator::visitSimdValueX4(MSimdValueX4*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdBinarySaturating(MSimdBinarySaturating*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSwizzle(MSimdSwizzle*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdShuffle(MSimdShuffle*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdGeneralShuffle(MSimdGeneralShuffle*)
+{
+    MOZ_CRASH("NYI");
+}
--- a/js/src/jit/arm64/Lowering-arm64.h
+++ b/js/src/jit/arm64/Lowering-arm64.h
@@ -9,22 +9,21 @@
 
 #include "jit/shared/Lowering-shared.h"
 
 namespace js {
 namespace jit {
 
 class LIRGeneratorARM64 : public LIRGeneratorShared
 {
-  public:
+  protected:
     LIRGeneratorARM64(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     { }
 
-  protected:
     // Returns a box allocation. reg2 is ignored on 64-bit platforms.
     LBoxAllocation useBoxFixed(MDefinition* mir, Register reg1, Register reg2,
                                bool useAtStart = false);
 
     LAllocation useByteOpRegister(MDefinition* mir);
     LAllocation useByteOpRegisterAtStart(MDefinition* mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition* mir);
 
@@ -82,50 +81,23 @@ class LIRGeneratorARM64 : public LIRGene
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
     void lowerDivI(MDiv* div);
     void lowerModI(MMod* mod);
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
-    void visitPowHalf(MPowHalf* ins);
-    void visitWasmNeg(MWasmNeg* ins);
-    void visitWasmSelect(MWasmSelect* ins);
 
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
     LTableSwitch* newLTableSwitch(const LAllocation& in,
                                   const LDefinition& inputCopy,
                                   MTableSwitch* ins);
 
-  public:
-    void visitBox(MBox* box);
-    void visitUnbox(MUnbox* unbox);
-    void visitReturn(MReturn* ret);
     void lowerPhi(MPhi* phi);
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
-    void visitSubstr(MSubstr* ins);
-    void visitRandom(MRandom* ins);
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
-    void visitWasmLoad(MWasmLoad* ins);
-    void visitWasmStore(MWasmStore* ins);
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
-    void visitCopySign(MCopySign* ins);
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
-    void visitSignExtendInt64(MSignExtendInt64* ins);
 };
 
 typedef LIRGeneratorARM64 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm64_Lowering_arm64_h */
--- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -260,17 +260,17 @@ LIRGeneratorMIPSShared::lowerModI(MMod* 
                            temp(LDefinition::GENERAL));
 
     if (mod->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
     define(lir, mod);
 }
 
 void
-LIRGeneratorMIPSShared::visitPowHalf(MPowHalf* ins)
+LIRGenerator::visitPowHalf(MPowHalf* ins)
 {
     MDefinition* input = ins->input();
     MOZ_ASSERT(input->type() == MIRType::Double);
     LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
     defineReuseInput(lir, ins, 0);
 }
 
 LTableSwitch*
@@ -296,30 +296,30 @@ LIRGeneratorMIPSShared::lowerUrshD(MUrsh
     MOZ_ASSERT(lhs->type() == MIRType::Int32);
     MOZ_ASSERT(rhs->type() == MIRType::Int32);
 
     LUrshD* lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
     define(lir, mir);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmNeg(MWasmNeg* ins)
+LIRGenerator::visitWasmNeg(MWasmNeg* ins)
 {
     if (ins->type() == MIRType::Int32) {
         define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
     } else if (ins->type() == MIRType::Float32) {
         define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
     } else {
         MOZ_ASSERT(ins->type() == MIRType::Double);
         define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
     }
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmLoad(MWasmLoad* ins)
+LIRGenerator::visitWasmLoad(MWasmLoad* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     LAllocation ptr;
 #ifdef JS_CODEGEN_MIPS32
     if (ins->type() == MIRType::Int64)
         ptr = useRegister(base);
@@ -365,17 +365,17 @@ LIRGeneratorMIPSShared::visitWasmLoad(MW
     auto* lir = new(alloc()) LWasmLoad(ptr);
     if (ins->access().offset())
         lir->setTemp(0, tempCopy(base, 0));
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmStore(MWasmStore* ins)
+LIRGenerator::visitWasmStore(MWasmStore* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* value = ins->value();
 
     if (IsUnaligned(ins->access())) {
         LAllocation baseAlloc = useRegisterAtStart(base);
@@ -423,17 +423,17 @@ LIRGeneratorMIPSShared::visitWasmStore(M
     auto* lir = new(alloc()) LWasmStore(baseAlloc, valueAlloc);
     if (ins->access().offset())
         lir->setTemp(0, tempCopy(base, 0));
 
     add(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmSelect(MWasmSelect* ins)
+LIRGenerator::visitWasmSelect(MWasmSelect* ins)
 {
     if (ins->type() == MIRType::Int64) {
         auto* lir = new(alloc()) LWasmSelectI64(useInt64RegisterAtStart(ins->trueExpr()),
                                                 useInt64(ins->falseExpr()),
                                                 useRegister(ins->condExpr()));
 
         defineInt64ReuseInput(lir, ins, LWasmSelectI64::TrueExprIndex);
         return;
@@ -472,33 +472,33 @@ LIRGeneratorMIPSShared::lowerUMod(MMod* 
     lir->setOperand(1, useRegister(rhs));
     if (mod->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
 
     define(lir, mod);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
+LIRGenerator::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToDouble* lir = new(alloc()) LWasmUint32ToDouble(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
+LIRGenerator::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToFloat32* lir = new(alloc()) LWasmUint32ToFloat32(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
+LIRGenerator::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
 {
     MOZ_ASSERT(ins->access().offset() == 0);
 
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
     LAllocation baseAlloc;
     LAllocation limitAlloc;
     // For MIPS it is best to keep the 'base' in a register if a bounds check
@@ -515,17 +515,17 @@ LIRGeneratorMIPSShared::visitAsmJSLoadHe
             limitAlloc = useRegisterAtStart(boundsCheckLimit);
         }
     }
 
     define(new(alloc()) LAsmJSLoadHeap(baseAlloc, limitAlloc), ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
+LIRGenerator::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
 {
     MOZ_ASSERT(ins->access().offset() == 0);
 
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
     LAllocation baseAlloc;
     LAllocation limitAlloc;
     if (base->isConstant() && !ins->needsBoundsCheck()) {
@@ -539,36 +539,36 @@ LIRGeneratorMIPSShared::visitAsmJSStoreH
             limitAlloc = useRegisterAtStart(boundsCheckLimit);
         }
     }
 
     add(new(alloc()) LAsmJSStoreHeap(baseAlloc, useRegisterAtStart(ins->value()), limitAlloc), ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitSubstr(MSubstr* ins)
+LIRGenerator::visitSubstr(MSubstr* ins)
 {
     LSubstr* lir = new (alloc()) LSubstr(useRegister(ins->string()),
                                          useRegister(ins->begin()),
                                          useRegister(ins->length()),
                                          temp(),
                                          temp(),
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
+LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPSShared::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
+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);
 
     const LUse elements = useRegister(ins->elements());
@@ -597,17 +597,17 @@ LIRGeneratorMIPSShared::visitCompareExch
     LCompareExchangeTypedArrayElement* lir =
         new(alloc()) LCompareExchangeTypedArrayElement(elements, index, oldval, newval, outTemp,
                                                       valueTemp, offsetTemp, maskTemp);
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
+LIRGenerator::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
 {
     MOZ_ASSERT(ins->arrayType() <= Scalar::Uint32);
 
     MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
     MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
 
     const LUse elements = useRegister(ins->elements());
     const LAllocation index = useRegisterOrConstant(ins->index());
@@ -635,17 +635,17 @@ LIRGeneratorMIPSShared::visitAtomicExcha
     LAtomicExchangeTypedArrayElement* lir =
         new(alloc()) LAtomicExchangeTypedArrayElement(elements, index, value, outTemp,
                                                       valueTemp, offsetTemp, maskTemp);
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
+LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
 {
     MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
 
     if (ins->access().type() == Scalar::Int64) {
         auto* lir = new(alloc()) LWasmCompareExchangeI64(useRegister(ins->base()),
                                                          useInt64Register(ins->oldValue()),
                                                          useInt64Register(ins->newValue()));
         defineInt64(lir, ins);
@@ -667,17 +667,17 @@ LIRGeneratorMIPSShared::visitWasmCompare
                                               useRegister(ins->oldValue()),
                                               useRegister(ins->newValue()),
                                               valueTemp, offsetTemp, maskTemp);
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
+LIRGenerator::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
 {
     MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
 
     if (ins->access().type() == Scalar::Int64) {
         auto* lir = new(alloc()) LWasmAtomicExchangeI64(useRegister(ins->base()),
                                                         useInt64Register(ins->value()));
         defineInt64(lir, ins);
         return;
@@ -696,17 +696,17 @@ LIRGeneratorMIPSShared::visitWasmAtomicE
     LWasmAtomicExchangeHeap* lir =
         new(alloc()) LWasmAtomicExchangeHeap(useRegister(ins->base()),
                                              useRegister(ins->value()),
                                              valueTemp, offsetTemp, maskTemp);
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
+LIRGenerator::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
 {
     MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
 
     if (ins->access().type() == Scalar::Int64) {
         auto* lir = new(alloc()) LWasmAtomicBinopI64(useRegister(ins->base()),
                                                      useInt64Register(ins->value()));
         lir->setTemp(0, temp());
 #ifdef JS_CODEGEN_MIPS32
@@ -739,17 +739,17 @@ LIRGeneratorMIPSShared::visitWasmAtomicB
         new(alloc()) LWasmAtomicBinopHeap(useRegister(ins->base()),
                                           useRegister(ins->value()),
                                           valueTemp, offsetTemp, maskTemp);
 
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
+LIRGenerator::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     MOZ_ASSERT(ins->arrayType() != Scalar::Uint8Clamped);
     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);
 
@@ -784,19 +784,18 @@ LIRGeneratorMIPSShared::visitAtomicTyped
         outTemp = temp();
 
     LAtomicTypedArrayElementBinop* lir =
         new(alloc()) LAtomicTypedArrayElementBinop(elements, index, value, outTemp,
                                                    valueTemp, offsetTemp, maskTemp);
     define(lir, ins);
 }
 
-
 void
-LIRGeneratorMIPSShared::visitCopySign(MCopySign* ins)
+LIRGenerator::visitCopySign(MCopySign* ins)
 {
     MDefinition* lhs = ins->lhs();
     MDefinition* rhs = ins->rhs();
 
     MOZ_ASSERT(IsFloatingPointType(lhs->type()));
     MOZ_ASSERT(lhs->type() == rhs->type());
     MOZ_ASSERT(lhs->type() == ins->type());
 
@@ -810,18 +809,78 @@ LIRGeneratorMIPSShared::visitCopySign(MC
     lir->setTemp(1, temp());
 
     lir->setOperand(0, useRegisterAtStart(lhs));
     lir->setOperand(1, useRegister(rhs));
     defineReuseInput(lir, ins, 0);
 }
 
 void
-LIRGeneratorMIPSShared::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
+LIRGenerator::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     defineInt64(new(alloc()) LExtendInt32ToInt64(useRegisterAtStart(ins->input())), ins);
 }
 
 void
-LIRGeneratorMIPSShared::visitSignExtendInt64(MSignExtendInt64* ins)
+LIRGenerator::visitSignExtendInt64(MSignExtendInt64* ins)
 {
     defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins);
 }
+
+void
+LIRGenerator::visitSimdInsertElement(MSimdInsertElement*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdExtractElement(MSimdExtractElement*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdBinaryArith(MSimdBinaryArith*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSelect(MSimdSelect*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSplat(MSimdSplat*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdValueX4(MSimdValueX4*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdBinarySaturating(MSimdBinarySaturating*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdSwizzle(MSimdSwizzle*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdShuffle(MSimdShuffle*)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+LIRGenerator::visitSimdGeneralShuffle(MSimdGeneralShuffle*)
+{
+    MOZ_CRASH("NYI");
+}
--- a/js/src/jit/mips-shared/Lowering-mips-shared.h
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.h
@@ -14,17 +14,16 @@ namespace jit {
 
 class LIRGeneratorMIPSShared : public LIRGeneratorShared
 {
   protected:
     LIRGeneratorMIPSShared(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     { }
 
-  protected:
     // x86 has constraints on what registers can be formatted for 1-byte
     // stores and loads; on MIPS all registers are okay.
     LAllocation useByteOpRegister(MDefinition* mir);
     LAllocation useByteOpRegisterAtStart(MDefinition* mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition* mir);
     LDefinition tempByteOpRegister();
 
     bool needTempForPostBarrier() { return false; }
@@ -64,42 +63,20 @@ class LIRGeneratorMIPSShared : public LI
 
     void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
                                  MDefinition* lhs, MDefinition* rhs);
     void lowerDivI(MDiv* div);
     void lowerModI(MMod* mod);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
-    void visitPowHalf(MPowHalf* ins);
-    void visitWasmNeg(MWasmNeg* ins);
-    void visitWasmLoad(MWasmLoad* ins);
-    void visitWasmStore(MWasmStore* ins);
-    void visitWasmSelect(MWasmSelect* ins);
 
     LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
                                   MTableSwitch* ins);
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
 
-  public:
     void lowerPhi(MPhi* phi);
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
-    void visitSubstr(MSubstr* ins);
-    void visitCopySign(MCopySign* ins);
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
-    void visitSignExtendInt64(MSignExtendInt64* ins);
-
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips_shared_Lowering_mips_shared_h */
--- a/js/src/jit/mips32/Lowering-mips32.cpp
+++ b/js/src/jit/mips32/Lowering-mips32.cpp
@@ -22,17 +22,17 @@ LIRGeneratorMIPS::useBoxFixed(MDefinitio
     MOZ_ASSERT(reg1 != reg2);
 
     ensureDefined(mir);
     return LBoxAllocation(LUse(reg1, mir->virtualRegister(), useAtStart),
                           LUse(reg2, VirtualRegisterOfPayload(mir), useAtStart));
 }
 
 void
-LIRGeneratorMIPS::visitBox(MBox* box)
+LIRGenerator::visitBox(MBox* box)
 {
     MDefinition* inner = box->getOperand(0);
 
     // If the box wrapped a double, it needs a new register.
     if (IsFloatingPointType(inner->type())) {
         defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner),
                                                  tempCopy(inner, 0), inner->type()), box);
         return;
@@ -62,17 +62,17 @@ LIRGeneratorMIPS::visitBox(MBox* box)
     // ignored.
     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
     lir->setDef(1, LDefinition::BogusTemp());
     box->setVirtualRegister(vreg);
     add(lir);
 }
 
 void
-LIRGeneratorMIPS::visitUnbox(MUnbox* unbox)
+LIRGenerator::visitUnbox(MUnbox* unbox)
 {
     MDefinition* inner = unbox->getOperand(0);
 
     if (inner->type() == MIRType::ObjectOrNull) {
         LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
         if (unbox->fallible())
             assignSnapshot(lir, unbox->bailoutKind());
         defineReuseInput(lir, unbox, 0);
@@ -107,17 +107,17 @@ LIRGeneratorMIPS::visitUnbox(MUnbox* unb
     // before the payload, it could be used as a Value without the type being
     // recoverable. Unbox's purpose is to eagerly kill the definition of a type
     // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
     // Instead, we create a new virtual register.
     defineReuseInput(lir, unbox, 0);
 }
 
 void
-LIRGeneratorMIPS::visitReturn(MReturn* ret)
+LIRGenerator::visitReturn(MReturn* ret)
 {
     MDefinition* opd = ret->getOperand(0);
     MOZ_ASSERT(opd->type() == MIRType::Value);
 
     LReturn* ins = new(alloc()) LReturn;
     ins->setOperand(0, LUse(JSReturnReg_Type));
     ins->setOperand(1, LUse(JSReturnReg_Data));
     fillBoxUses(ins, 0, opd);
@@ -242,37 +242,37 @@ void
 LIRGeneratorMIPS::lowerUModI64(MMod* mod)
 {
     LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
                                                     useInt64RegisterAtStart(mod->rhs()));
     defineReturn(lir, mod);
 }
 
 void
-LIRGeneratorMIPS::visitRandom(MRandom* ins)
+LIRGenerator::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(),
                                         temp(),
                                         temp(),
                                         temp(),
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 
 void
-LIRGeneratorMIPS::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
+LIRGenerator::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
 
     defineReturn(new(alloc()) LWasmTruncateToInt64(useRegisterAtStart(opd)), ins);
 }
 
 void
-LIRGeneratorMIPS::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+LIRGenerator::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
     defineReturn(new(alloc()) LInt64ToFloatingPoint(useInt64RegisterAtStart(opd)), ins);
 }
--- a/js/src/jit/mips32/Lowering-mips32.h
+++ b/js/src/jit/mips32/Lowering-mips32.h
@@ -14,17 +14,16 @@ namespace jit {
 
 class LIRGeneratorMIPS : public LIRGeneratorMIPSShared
 {
   protected:
     LIRGeneratorMIPS(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorMIPSShared(gen, graph, lirGraph)
     { }
 
-  protected:
     // Returns a box allocation with type set to reg1 and payload set to reg2.
     LBoxAllocation useBoxFixed(MDefinition* mir, Register reg1, Register reg2,
                                bool useAtStart = false);
 
     inline LDefinition tempToUnbox() {
         return LDefinition::BogusTemp();
     }
 
@@ -36,24 +35,16 @@ class LIRGeneratorMIPS : public LIRGener
 
     void lowerTruncateDToInt32(MTruncateToInt32* ins);
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
 
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
-
-  public:
-    void visitBox(MBox* box);
-    void visitUnbox(MUnbox* unbox);
-    void visitReturn(MReturn* ret);
-    void visitRandom(MRandom* ins);
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
 };
 
 typedef LIRGeneratorMIPS LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips32_Lowering_mips32_h */
--- a/js/src/jit/mips64/Lowering-mips64.cpp
+++ b/js/src/jit/mips64/Lowering-mips64.cpp
@@ -77,17 +77,17 @@ LIRGeneratorMIPS64::lowerUModI64(MMod* m
 {
     LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(mod->lhs()),
                                                     useRegister(mod->rhs()),
                                                     temp());
     defineInt64(lir, mod);
 }
 
 void
-LIRGeneratorMIPS64::visitBox(MBox* box)
+LIRGenerator::visitBox(MBox* box)
 {
     MDefinition* opd = box->getOperand(0);
 
     // If the operand is a constant, emit near its uses.
     if (opd->isConstant() && box->canEmitAtUses()) {
         emitAtUses(box);
         return;
     }
@@ -96,17 +96,17 @@ LIRGeneratorMIPS64::visitBox(MBox* box)
         define(new(alloc()) LValue(opd->toConstant()->toJSValue()), box, LDefinition(LDefinition::BOX));
     } else {
         LBox* ins = new(alloc()) LBox(useRegister(opd), opd->type());
         define(ins, box, LDefinition(LDefinition::BOX));
     }
 }
 
 void
-LIRGeneratorMIPS64::visitUnbox(MUnbox* unbox)
+LIRGenerator::visitUnbox(MUnbox* unbox)
 {
     MDefinition* box = unbox->getOperand(0);
 
     if (box->type() == MIRType::ObjectOrNull) {
         LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(box));
         if (unbox->fallible())
             assignSnapshot(lir, unbox->bailoutKind());
         defineReuseInput(lir, unbox, 0);
@@ -128,17 +128,17 @@ LIRGeneratorMIPS64::visitUnbox(MUnbox* u
 
     if (unbox->fallible())
         assignSnapshot(lir, unbox->bailoutKind());
 
     define(lir, unbox);
 }
 
 void
-LIRGeneratorMIPS64::visitReturn(MReturn* ret)
+LIRGenerator::visitReturn(MReturn* ret)
 {
     MDefinition* opd = ret->getOperand(0);
     MOZ_ASSERT(opd->type() == MIRType::Value);
 
     LReturn* ins = new(alloc()) LReturn;
     ins->setOperand(0, useFixed(opd, JSReturnReg));
     add(ins);
 }
@@ -172,33 +172,33 @@ LIRGeneratorMIPS64::lowerTruncateFToInt3
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Float32);
 
     define(new(alloc())
            LTruncateFToInt32(useRegister(opd), tempFloat32()), ins);
 }
 
 void
-LIRGeneratorMIPS64::visitRandom(MRandom* ins)
+LIRGenerator::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(), temp(), temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 
 void
-LIRGeneratorMIPS64::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
+LIRGenerator::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
 
     defineInt64(new(alloc()) LWasmTruncateToInt64(useRegister(opd)), ins);
 }
 
 void
-LIRGeneratorMIPS64::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+LIRGenerator::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
     define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd)), ins);
 }
--- a/js/src/jit/mips64/Lowering-mips64.h
+++ b/js/src/jit/mips64/Lowering-mips64.h
@@ -14,17 +14,16 @@ namespace jit {
 
 class LIRGeneratorMIPS64 : public LIRGeneratorMIPSShared
 {
   protected:
     LIRGeneratorMIPS64(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorMIPSShared(gen, graph, lirGraph)
     { }
 
-  protected:
     void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t);
     void defineInt64Phi(MPhi*, size_t);
 
     // Returns a box allocation. reg2 is ignored on 64-bit platforms.
     LBoxAllocation useBoxFixed(MDefinition* mir, Register reg1, Register reg2,
                                bool useAtStart = false);
 
     inline LDefinition tempToUnbox() {
@@ -36,24 +35,16 @@ class LIRGeneratorMIPS64 : public LIRGen
 
     void lowerTruncateDToInt32(MTruncateToInt32* ins);
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
 
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
-
-  public:
-    void visitBox(MBox* box);
-    void visitUnbox(MUnbox* unbox);
-    void visitReturn(MReturn* ret);
-    void visitRandom(MRandom* ins);
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
 };
 
 typedef LIRGeneratorMIPS64 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips64_Lowering_mips64_h */
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -9,17 +9,17 @@
 
 #include "jit/shared/Lowering-shared.h"
 
 namespace js {
 namespace jit {
 
 class LIRGeneratorNone : public LIRGeneratorShared
 {
-  public:
+  protected:
     LIRGeneratorNone(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     {
         MOZ_CRASH();
     }
 
     LBoxAllocation useBoxFixed(MDefinition*, Register, Register, bool useAtStart = false) { MOZ_CRASH(); }
 
@@ -65,53 +65,19 @@ class LIRGeneratorNone : public LIRGener
     void lowerTruncateFToInt32(MTruncateToInt32*) { MOZ_CRASH(); }
     void lowerDivI(MDiv*) { MOZ_CRASH(); }
     void lowerModI(MMod*) { MOZ_CRASH(); }
     void lowerDivI64(MDiv*) { MOZ_CRASH(); }
     void lowerModI64(MMod*) { MOZ_CRASH(); }
     void lowerMulI(MMul*, MDefinition*, MDefinition*) { MOZ_CRASH(); }
     void lowerUDiv(MDiv*) { MOZ_CRASH(); }
     void lowerUMod(MMod*) { MOZ_CRASH(); }
-    void visitBox(MBox* box) { MOZ_CRASH(); }
-    void visitUnbox(MUnbox* unbox) { MOZ_CRASH(); }
-    void visitReturn(MReturn* ret) { MOZ_CRASH(); }
-    void visitPowHalf(MPowHalf*) { MOZ_CRASH(); }
-    void visitWasmNeg(MWasmNeg*) { MOZ_CRASH(); }
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) { MOZ_CRASH(); }
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins) { MOZ_CRASH(); }
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins) { MOZ_CRASH(); }
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) { MOZ_CRASH(); }
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) { MOZ_CRASH(); }
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) { MOZ_CRASH(); }
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) { MOZ_CRASH(); }
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) { MOZ_CRASH(); }
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) { MOZ_CRASH(); }
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) { MOZ_CRASH(); }
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) { MOZ_CRASH(); }
-    void visitWasmSelect(MWasmSelect*) { MOZ_CRASH(); }
-    void visitWasmBoundsCheck(MWasmBoundsCheck* ins) { MOZ_CRASH(); }
-    void visitWasmLoad(MWasmLoad* ins) { MOZ_CRASH(); }
-    void visitWasmStore(MWasmStore* ins) { MOZ_CRASH(); }
 
     LTableSwitch* newLTableSwitch(LAllocation, LDefinition, MTableSwitch*) { MOZ_CRASH(); }
     LTableSwitchV* newLTableSwitchV(MTableSwitch*) { MOZ_CRASH(); }
-    void visitSimdSelect(MSimdSelect* ins) { MOZ_CRASH(); }
-    void visitSimdSplat(MSimdSplat* ins) { MOZ_CRASH(); }
-    void visitSimdSwizzle(MSimdSwizzle* ins) { MOZ_CRASH(); }
-    void visitSimdShuffle(MSimdShuffle* ins) { MOZ_CRASH(); }
-    void visitSimdValueX4(MSimdValueX4* lir) { MOZ_CRASH(); }
-    void visitSubstr(MSubstr*) { MOZ_CRASH(); }
-    void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); }
-    void visitSimdBinarySaturating(MSimdBinarySaturating* ins) { MOZ_CRASH(); }
-    void visitRandom(js::jit::MRandom*) { MOZ_CRASH(); }
-    void visitCopySign(js::jit::MCopySign*) { MOZ_CRASH(); }
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64*) { MOZ_CRASH(); }
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint*) { MOZ_CRASH(); }
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins) { MOZ_CRASH(); }
-    void visitSignExtendInt64(MSignExtendInt64* ins) { MOZ_CRASH(); }
 };
 
 typedef LIRGeneratorNone LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_none_Lowering_none_h */
--- a/js/src/jit/shared/Lowering-shared.cpp
+++ b/js/src/jit/shared/Lowering-shared.cpp
@@ -2,16 +2,17 @@
  * 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 "jit/shared/Lowering-shared-inl.h"
 
 #include "jit/LIR.h"
+#include "jit/Lowering.h"
 #include "jit/MIR.h"
 
 #include "vm/SymbolType.h"
 
 using namespace js;
 using namespace jit;
 
 bool
@@ -67,71 +68,16 @@ LIRGeneratorShared::ReorderCommutative(M
 
     if (ShouldReorderCommutative(lhs, rhs, ins)) {
         *rhsp = lhs;
         *lhsp = rhs;
     }
 }
 
 void
-LIRGeneratorShared::visitConstant(MConstant* ins)
-{
-    if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
-        emitAtUses(ins);
-        return;
-    }
-
-    switch (ins->type()) {
-      case MIRType::Double:
-        define(new(alloc()) LDouble(ins->toDouble()), ins);
-        break;
-      case MIRType::Float32:
-        define(new(alloc()) LFloat32(ins->toFloat32()), ins);
-        break;
-      case MIRType::Boolean:
-        define(new(alloc()) LInteger(ins->toBoolean()), ins);
-        break;
-      case MIRType::Int32:
-        define(new(alloc()) LInteger(ins->toInt32()), ins);
-        break;
-      case MIRType::Int64:
-        defineInt64(new(alloc()) LInteger64(ins->toInt64()), ins);
-        break;
-      case MIRType::String:
-        define(new(alloc()) LPointer(ins->toString()), ins);
-        break;
-      case MIRType::Symbol:
-        define(new(alloc()) LPointer(ins->toSymbol()), ins);
-        break;
-      case MIRType::Object:
-        define(new(alloc()) LPointer(&ins->toObject()), ins);
-        break;
-      default:
-        // Constants of special types (undefined, null) should never flow into
-        // here directly. Operations blindly consuming them require a Box.
-        MOZ_CRASH("unexpected constant type");
-    }
-}
-
-void
-LIRGeneratorShared::visitWasmFloatConstant(MWasmFloatConstant* ins)
-{
-    switch (ins->type()) {
-      case MIRType::Double:
-        define(new(alloc()) LDouble(ins->toDouble()), ins);
-        break;
-      case MIRType::Float32:
-        define(new(alloc()) LFloat32(ins->toFloat32()), ins);
-        break;
-      default:
-        MOZ_CRASH("unexpected constant type");
-    }
-}
-
-void
 LIRGeneratorShared::defineTypedPhi(MPhi* phi, size_t lirIndex)
 {
     LPhi* lir = current->getPhi(lirIndex);
 
     uint32_t vreg = getVirtualRegister();
 
     phi->setVirtualRegister(vreg);
     lir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(phi->type())));
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -28,17 +28,16 @@ class LIRGeneratorShared
     MIRGenerator* gen;
     MIRGraph& graph;
     LIRGraph& lirGraph_;
     LBlock* current;
     MResumePoint* lastResumePoint_;
     LRecoverInfo* cachedRecoverInfo_;
     LOsiPoint* osiPoint_;
 
-  public:
     LIRGeneratorShared(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : gen(gen),
         graph(graph),
         lirGraph_(lirGraph),
         lastResumePoint_(nullptr),
         cachedRecoverInfo_(nullptr),
         osiPoint_(nullptr)
     { }
@@ -58,18 +57,16 @@ class LIRGeneratorShared
         va_end(ap);
         gen->setOffThreadStatus(reason_);
     }
     void abort(AbortReason r) {
         auto reason_ = gen->abort(r);
         gen->setOffThreadStatus(reason_);
     }
 
-  protected:
-
     static void ReorderCommutative(MDefinition** lhsp, MDefinition** rhsp, MInstruction* ins);
     static bool ShouldReorderCommutative(MDefinition* lhs, MDefinition* rhs, MInstruction* ins);
 
     // A backend can decide that an instruction should be emitted at its uses,
     // rather than at its definition. To communicate this, set the
     // instruction's virtual register set to 0. When using the instruction,
     // its virtual register is temporarily reassigned. To know to clear it
     // after constructing the use information, the worklist bit is temporarily
@@ -276,50 +273,31 @@ class LIRGeneratorShared
     void assignSnapshot(LInstruction* ins, BailoutKind kind);
 
     // Marks this instruction as needing to call into either the VM or GC. This
     // function may build a snapshot that captures the result of its own
     // instruction, and as such, should generally be called after define*().
     void assignSafepoint(LInstruction* ins, MInstruction* mir,
                          BailoutKind kind = Bailout_DuringVMCall);
 
-  public:
     void lowerConstantDouble(double d, MInstruction* mir) {
         define(new(alloc()) LDouble(d), mir);
     }
     void lowerConstantFloat32(float f, MInstruction* mir) {
         define(new(alloc()) LFloat32(f), mir);
     }
 
-    void visitConstant(MConstant* ins);
-    void visitWasmFloatConstant(MWasmFloatConstant* ins);
-
+  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;
     }
-
-    // Provide NYI default implementations of the SIMD visitor functions.
-    // Many targets don't implement SIMD at all, and we don't want to duplicate
-    // these stubs in the specific sub-classes.
-    // Some SIMD visitors are implemented in LIRGenerator in Lowering.cpp. These
-    // shared implementations are not included here.
-    void visitSimdInsertElement(MSimdInsertElement*) { MOZ_CRASH("NYI"); }
-    void visitSimdExtractElement(MSimdExtractElement*) { MOZ_CRASH("NYI"); }
-    void visitSimdBinaryArith(MSimdBinaryArith*) { MOZ_CRASH("NYI"); }
-    void visitSimdSelect(MSimdSelect*) { MOZ_CRASH("NYI"); }
-    void visitSimdSplat(MSimdSplat*) { MOZ_CRASH("NYI"); }
-    void visitSimdValueX4(MSimdValueX4*) { MOZ_CRASH("NYI"); }
-    void visitSimdBinarySaturating(MSimdBinarySaturating*) { MOZ_CRASH("NYI"); }
-    void visitSimdSwizzle(MSimdSwizzle*) { MOZ_CRASH("NYI"); }
-    void visitSimdShuffle(MSimdShuffle*) { MOZ_CRASH("NYI"); }
-    void visitSimdGeneralShuffle(MSimdGeneralShuffle*) { MOZ_CRASH("NYI"); }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_Lowering_shared_h */
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "jit/x64/Lowering-x64.h"
 
+#include "jit/Lowering.h"
 #include "jit/MIR.h"
 #include "jit/x64/Assembler-x64.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
@@ -69,17 +70,17 @@ LIRGeneratorX64::lowerForMulInt64(LMulI6
     // X64 doesn't need a temp for 64bit multiplication.
     ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
     ins->setInt64Operand(INT64_PIECES,
                          lhs != rhs ? useInt64OrConstant(rhs) : useInt64OrConstantAtStart(rhs));
     defineInt64ReuseInput(ins, mir, 0);
 }
 
 void
-LIRGeneratorX64::visitBox(MBox* box)
+LIRGenerator::visitBox(MBox* box)
 {
     MDefinition* opd = box->getOperand(0);
 
     // If the operand is a constant, emit near its uses.
     if (opd->isConstant() && box->canEmitAtUses()) {
         emitAtUses(box);
         return;
     }
@@ -88,17 +89,17 @@ LIRGeneratorX64::visitBox(MBox* box)
         define(new(alloc()) LValue(opd->toConstant()->toJSValue()), box, LDefinition(LDefinition::BOX));
     } else {
         LBox* ins = new(alloc()) LBox(useRegister(opd), opd->type());
         define(ins, box, LDefinition(LDefinition::BOX));
     }
 }
 
 void
-LIRGeneratorX64::visitUnbox(MUnbox* unbox)
+LIRGenerator::visitUnbox(MUnbox* unbox)
 {
     MDefinition* box = unbox->getOperand(0);
 
     if (box->type() == MIRType::ObjectOrNull) {
         LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(box));
         if (unbox->fallible())
             assignSnapshot(lir, unbox->bailoutKind());
         defineReuseInput(lir, unbox, 0);
@@ -120,17 +121,17 @@ LIRGeneratorX64::visitUnbox(MUnbox* unbo
 
     if (unbox->fallible())
         assignSnapshot(lir, unbox->bailoutKind());
 
     define(lir, unbox);
 }
 
 void
-LIRGeneratorX64::visitReturn(MReturn* ret)
+LIRGenerator::visitReturn(MReturn* ret)
 {
     MDefinition* opd = ret->getOperand(0);
     MOZ_ASSERT(opd->type() == MIRType::Value);
 
     LReturn* ins = new(alloc()) LReturn;
     ins->setOperand(0, useFixed(opd, JSReturnReg));
     add(ins);
 }
@@ -155,67 +156,67 @@ LIRGeneratorX64::defineInt64Phi(MPhi* ph
 
 void
 LIRGeneratorX64::lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex)
 {
     lowerTypedPhiInput(phi, inputPosition, block, lirIndex);
 }
 
 void
-LIRGeneratorX64::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
+LIRGenerator::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
     lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ false);
 }
 
 void
-LIRGeneratorX64::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
+LIRGenerator::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
 {
     lowerAtomicExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ false);
 }
 
 void
-LIRGeneratorX64::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
+LIRGenerator::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     lowerAtomicTypedArrayElementBinop(ins, /* useI386ByteRegisters = */ false);
 }
 
 void
-LIRGeneratorX64::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
+LIRGenerator::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToDouble* lir = new(alloc()) LWasmUint32ToDouble(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
+LIRGenerator::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToFloat32* lir = new(alloc()) LWasmUint32ToFloat32(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitWasmLoad(MWasmLoad* ins)
+LIRGenerator::visitWasmLoad(MWasmLoad* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     if (ins->type() != MIRType::Int64) {
         auto* lir = new(alloc()) LWasmLoad(useRegisterOrZeroAtStart(base));
         define(lir, ins);
         return;
     }
 
     auto* lir = new(alloc()) LWasmLoadI64(useRegisterOrZeroAtStart(base));
     defineInt64(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitWasmStore(MWasmStore* ins)
+LIRGenerator::visitWasmStore(MWasmStore* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* value = ins->value();
     LAllocation valueAlloc;
     switch (ins->access().type()) {
       case Scalar::Int8:
@@ -247,26 +248,26 @@ LIRGeneratorX64::visitWasmStore(MWasmSto
     }
 
     LAllocation baseAlloc = useRegisterOrZeroAtStart(base);
     auto* lir = new(alloc()) LWasmStore(baseAlloc, valueAlloc);
     add(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
+LIRGenerator::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     define(new(alloc()) LAsmJSLoadHeap(useRegisterOrZeroAtStart(base)), ins);
 }
 
 void
-LIRGeneratorX64::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
+LIRGenerator::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     LAsmJSStoreHeap* lir = nullptr;  // initialize to silence GCC warning
     switch (ins->access().type()) {
       case Scalar::Int8:
       case Scalar::Uint8:
@@ -290,17 +291,17 @@ LIRGeneratorX64::visitAsmJSStoreHeap(MAs
       case Scalar::Uint8Clamped:
       case Scalar::MaxTypedArrayViewType:
         MOZ_CRASH("unexpected array type");
     }
     add(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
+LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     // The output may not be used but will be clobbered regardless, so
     // pin the output to eax.
     //
     // The input values must both be in registers.
@@ -310,34 +311,34 @@ LIRGeneratorX64::visitWasmCompareExchang
 
     LWasmCompareExchangeHeap* lir =
         new(alloc()) LWasmCompareExchangeHeap(useRegister(base), oldval, newval);
 
     defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
 }
 
 void
-LIRGeneratorX64::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
+LIRGenerator::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
 {
     MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
 
     const LAllocation base = useRegister(ins->base());
     const LAllocation value = useRegister(ins->value());
 
     // The output may not be used but will be clobbered regardless,
     // so ignore the case where we're not using the value and just
     // use the output register as a temp.
 
     LWasmAtomicExchangeHeap* lir =
         new(alloc()) LWasmAtomicExchangeHeap(base, value);
     define(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
+LIRGenerator::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     // No support for 64-bit operations with constants at the masm level.
 
     bool canTakeConstant = ins->access().type() != Scalar::Int64;
 
@@ -398,36 +399,36 @@ LIRGeneratorX64::visitWasmAtomicBinopHea
         defineReuseInput(lir, ins, LWasmAtomicBinopHeap::valueOp);
     else if (bitOp)
         defineFixed(lir, ins, LAllocation(AnyRegister(rax)));
     else
         define(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitSubstr(MSubstr* ins)
+LIRGenerator::visitSubstr(MSubstr* ins)
 {
     LSubstr* lir = new (alloc()) LSubstr(useRegister(ins->string()),
                                          useRegister(ins->begin()),
                                          useRegister(ins->length()),
                                          temp(),
                                          temp(),
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGeneratorX64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
+LIRGenerator::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorX64::visitRandom(MRandom* ins)
+LIRGenerator::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(),
                                         temp(),
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
@@ -470,39 +471,39 @@ LIRGeneratorX64::lowerUModI64(MMod* mod)
 {
     LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(mod->lhs()),
                                                     useRegister(mod->rhs()),
                                                     tempFixed(rax));
     defineInt64Fixed(lir, mod, LInt64Allocation(LAllocation(AnyRegister(rdx))));
 }
 
 void
-LIRGeneratorX64::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
+LIRGenerator::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
 
     LDefinition maybeTemp = ins->isUnsigned() ? tempDouble() : LDefinition::BogusTemp();
     defineInt64(new(alloc()) LWasmTruncateToInt64(useRegister(opd), maybeTemp), ins);
 }
 
 void
-LIRGeneratorX64::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+LIRGenerator::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
     LDefinition maybeTemp = ins->isUnsigned() ? temp() : LDefinition::BogusTemp();
     define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), maybeTemp), ins);
 }
 
 void
-LIRGeneratorX64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
+LIRGenerator::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     defineInt64(new(alloc()) LExtendInt32ToInt64(useAtStart(ins->input())), ins);
 }
 
 void
-LIRGeneratorX64::visitSignExtendInt64(MSignExtendInt64* ins)
+LIRGenerator::visitSignExtendInt64(MSignExtendInt64* ins)
 {
     defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins);
 }
--- a/js/src/jit/x64/Lowering-x64.h
+++ b/js/src/jit/x64/Lowering-x64.h
@@ -9,22 +9,21 @@
 
 #include "jit/x86-shared/Lowering-x86-shared.h"
 
 namespace js {
 namespace jit {
 
 class LIRGeneratorX64 : public LIRGeneratorX86Shared
 {
-  public:
+  protected:
     LIRGeneratorX64(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorX86Shared(gen, graph, lirGraph)
     { }
 
-  protected:
     void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineUntypedPhi(MPhi* phi, size_t lirIndex);
     void lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineInt64Phi(MPhi* phi, size_t lirIndex);
 
     void lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
                           MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
     void lowerForMulInt64(LMulI64* ins, MMul* mir, MDefinition* lhs, MDefinition* rhs);
@@ -42,40 +41,16 @@ class LIRGeneratorX64 : public LIRGenera
     LDefinition tempToUnbox();
 
     bool needTempForPostBarrier() { return true; }
 
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
-
-  public:
-    void visitBox(MBox* box);
-    void visitUnbox(MUnbox* unbox);
-    void visitReturn(MReturn* ret);
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
-    void visitWasmLoad(MWasmLoad* ins);
-    void visitWasmStore(MWasmStore* ins);
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
-    void visitSubstr(MSubstr* ins);
-    void visitRandom(MRandom* ins);
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
-    void visitSignExtendInt64(MSignExtendInt64* ins);
 };
 
 typedef LIRGeneratorX64 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_Lowering_x64_h */
--- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/x86-shared/Lowering-x86-shared.h"
 
 #include "mozilla/MathAlgorithms.h"
 
+#include "jit/Lowering.h"
 #include "jit/MIR.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::Abs;
@@ -29,17 +30,17 @@ LIRGeneratorX86Shared::newLTableSwitch(c
 LTableSwitchV*
 LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch* tableswitch)
 {
     return new(alloc()) LTableSwitchV(useBox(tableswitch->getOperand(0)),
                                       temp(), tempDouble(), temp(), tableswitch);
 }
 
 void
-LIRGeneratorX86Shared::visitPowHalf(MPowHalf* ins)
+LIRGenerator::visitPowHalf(MPowHalf* ins)
 {
     MDefinition* input = ins->input();
     MOZ_ASSERT(input->type() == MIRType::Double);
     LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
     define(lir, ins);
 }
 
 void
@@ -261,17 +262,17 @@ LIRGeneratorX86Shared::lowerModI(MMod* m
                                     useRegister(mod->rhs()),
                                     tempFixed(eax));
     if (mod->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
     defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
 }
 
 void
-LIRGeneratorX86Shared::visitWasmSelect(MWasmSelect* ins)
+LIRGenerator::visitWasmSelect(MWasmSelect* ins)
 {
     if (ins->type() == MIRType::Int64) {
         auto* lir = new(alloc()) LWasmSelectI64(useInt64RegisterAtStart(ins->trueExpr()),
                                                 useInt64(ins->falseExpr()),
                                                 useRegister(ins->condExpr()));
 
         defineInt64ReuseInput(lir, ins, LWasmSelectI64::TrueExprIndex);
         return;
@@ -280,17 +281,17 @@ LIRGeneratorX86Shared::visitWasmSelect(M
     auto* lir = new(alloc()) LWasmSelect(useRegisterAtStart(ins->trueExpr()),
                                          use(ins->falseExpr()),
                                          useRegister(ins->condExpr()));
 
     defineReuseInput(lir, ins, LWasmSelect::TrueExprIndex);
 }
 
 void
-LIRGeneratorX86Shared::visitWasmNeg(MWasmNeg* ins)
+LIRGenerator::visitWasmNeg(MWasmNeg* ins)
 {
     switch (ins->type()) {
       case MIRType::Int32:
         defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins, 0);
         break;
       case MIRType::Float32:
         defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins, 0);
         break;
@@ -605,17 +606,17 @@ LIRGeneratorX86Shared::lowerAtomicTypedA
         defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
     else if (reuseInput)
         defineReuseInput(lir, ins, LAtomicTypedArrayElementBinop::valueOp);
     else
         define(lir, ins);
 }
 
 void
-LIRGeneratorX86Shared::visitSimdInsertElement(MSimdInsertElement* ins)
+LIRGenerator::visitSimdInsertElement(MSimdInsertElement* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     LUse vec = useRegisterAtStart(ins->vector());
     LUse val = useRegister(ins->value());
     switch (ins->type()) {
       case MIRType::Int8x16:
       case MIRType::Bool8x16:
@@ -638,17 +639,17 @@ LIRGeneratorX86Shared::visitSimdInsertEl
         defineReuseInput(new(alloc()) LSimdInsertElementF(vec, val), ins, 0);
         break;
       default:
         MOZ_CRASH("Unknown SIMD kind when generating constant");
     }
 }
 
 void
-LIRGeneratorX86Shared::visitSimdExtractElement(MSimdExtractElement* ins)
+LIRGenerator::visitSimdExtractElement(MSimdExtractElement* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->input()->type()));
     MOZ_ASSERT(!IsSimdType(ins->type()));
 
     switch (ins->input()->type()) {
       case MIRType::Int8x16:
       case MIRType::Int16x8:
       case MIRType::Int32x4: {
@@ -690,17 +691,17 @@ LIRGeneratorX86Shared::visitSimdExtractE
         break;
       }
       default:
         MOZ_CRASH("Unknown SIMD kind when extracting element");
     }
 }
 
 void
-LIRGeneratorX86Shared::visitSimdBinaryArith(MSimdBinaryArith* ins)
+LIRGenerator::visitSimdBinaryArith(MSimdBinaryArith* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     MDefinition* lhs = ins->lhs();
     MDefinition* rhs = ins->rhs();
 
@@ -744,34 +745,34 @@ LIRGeneratorX86Shared::visitSimdBinaryAr
       }
 
       default:
         MOZ_CRASH("unknown simd type on binary arith operation");
     }
 }
 
 void
-LIRGeneratorX86Shared::visitSimdBinarySaturating(MSimdBinarySaturating* ins)
+LIRGenerator::visitSimdBinarySaturating(MSimdBinarySaturating* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     MDefinition* lhs = ins->lhs();
     MDefinition* rhs = ins->rhs();
 
     if (ins->isCommutative())
         ReorderCommutative(&lhs, &rhs, ins);
 
     LSimdBinarySaturating* lir = new (alloc()) LSimdBinarySaturating();
     lowerForFPU(lir, ins, lhs, rhs);
 }
 
 void
-LIRGeneratorX86Shared::visitSimdSelect(MSimdSelect* ins)
+LIRGenerator::visitSimdSelect(MSimdSelect* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     LSimdSelect* lins = new(alloc()) LSimdSelect;
     MDefinition* r0 = ins->getOperand(0);
     MDefinition* r1 = ins->getOperand(1);
     MDefinition* r2 = ins->getOperand(2);
 
@@ -779,17 +780,17 @@ LIRGeneratorX86Shared::visitSimdSelect(M
     lins->setOperand(1, useRegister(r1));
     lins->setOperand(2, useRegister(r2));
     lins->setTemp(0, temp(LDefinition::SIMD128FLOAT));
 
     define(lins, ins);
 }
 
 void
-LIRGeneratorX86Shared::visitSimdSplat(MSimdSplat* ins)
+LIRGenerator::visitSimdSplat(MSimdSplat* ins)
 {
     LAllocation x = useRegisterAtStart(ins->getOperand(0));
 
     switch (ins->type()) {
       case MIRType::Int8x16:
         define(new (alloc()) LSimdSplatX16(x), ins);
         break;
       case MIRType::Int16x8:
@@ -810,17 +811,17 @@ LIRGeneratorX86Shared::visitSimdSplat(MS
         define(new (alloc()) LSimdSplatX4(x), ins);
         break;
       default:
         MOZ_CRASH("Unknown SIMD kind");
     }
 }
 
 void
-LIRGeneratorX86Shared::visitSimdValueX4(MSimdValueX4* ins)
+LIRGenerator::visitSimdValueX4(MSimdValueX4* ins)
 {
     switch (ins->type()) {
       case MIRType::Float32x4: {
         // Ideally, x would be used at start and reused for the output, however
         // register allocation currently doesn't permit us to tie together two
         // virtual registers with different types.
         LAllocation x = useRegister(ins->getOperand(0));
         LAllocation y = useRegister(ins->getOperand(1));
@@ -841,17 +842,17 @@ LIRGeneratorX86Shared::visitSimdValueX4(
         break;
       }
       default:
         MOZ_CRASH("Unknown SIMD kind");
     }
 }
 
 void
-LIRGeneratorX86Shared::visitSimdSwizzle(MSimdSwizzle* ins)
+LIRGenerator::visitSimdSwizzle(MSimdSwizzle* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->input()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     if (IsIntegerSimdType(ins->input()->type())) {
         LUse use = useRegisterAtStart(ins->input());
         LSimdSwizzleI* lir = new (alloc()) LSimdSwizzleI(use);
         define(lir, ins);
@@ -872,17 +873,17 @@ LIRGeneratorX86Shared::visitSimdSwizzle(
         define(lir, ins);
         lir->setTemp(0, LDefinition::BogusTemp());
     } else {
         MOZ_CRASH("Unknown SIMD kind when getting lane");
     }
 }
 
 void
-LIRGeneratorX86Shared::visitSimdShuffle(MSimdShuffle* ins)
+LIRGenerator::visitSimdShuffle(MSimdShuffle* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
     if (ins->type() == MIRType::Int32x4 || ins->type() == MIRType::Float32x4) {
         bool zFromLHS = ins->lane(2) < 4;
         bool wFromLHS = ins->lane(3) < 4;
         uint32_t lanesFromLHS = (ins->lane(0) < 4) + (ins->lane(1) < 4) + zFromLHS + wFromLHS;
@@ -911,17 +912,17 @@ LIRGeneratorX86Shared::visitSimdShuffle(
 #else
             lir->setTemp(0, temp());
 #endif
         }
     }
 }
 
 void
-LIRGeneratorX86Shared::visitSimdGeneralShuffle(MSimdGeneralShuffle* ins)
+LIRGenerator::visitSimdGeneralShuffle(MSimdGeneralShuffle* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     size_t numOperands = ins->numVectors() + ins->numLanes();
 
     LSimdGeneralShuffleBase* lir;
     if (IsIntegerSimdType(ins->type())) {
 #if defined(JS_CODEGEN_X86)
@@ -957,17 +958,17 @@ LIRGeneratorX86Shared::visitSimdGeneralS
         lir->setOperand(i + ins->numVectors(), use(ins->lane(i)));
     }
 
     assignSnapshot(lir, Bailout_BoundsCheck);
     define(lir, ins);
 }
 
 void
-LIRGeneratorX86Shared::visitCopySign(MCopySign* ins)
+LIRGenerator::visitCopySign(MCopySign* ins)
 {
     MDefinition* lhs = ins->lhs();
     MDefinition* rhs = ins->rhs();
 
     MOZ_ASSERT(IsFloatingPointType(lhs->type()));
     MOZ_ASSERT(lhs->type() == rhs->type());
     MOZ_ASSERT(lhs->type() == ins->type());
 
--- a/js/src/jit/x86-shared/Lowering-x86-shared.h
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.h
@@ -18,17 +18,16 @@ class LIRGeneratorX86Shared : public LIR
     LIRGeneratorX86Shared(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     {}
 
     LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
                                   MTableSwitch* ins);
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
 
-    void visitPowHalf(MPowHalf* ins);
     void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                        MDefinition* rhs);
     void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir, MDefinition* input);
     void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                      MDefinition* rhs);
 
     template<size_t Temps>
     void lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, Temps>* ins,
@@ -38,41 +37,28 @@ class LIRGeneratorX86Shared : public LIR
     void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs,
                      MDefinition* rhs);
     void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
                          MDefinition* lhs, MDefinition* rhs);
     void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir,
                          MDefinition* lhs, MDefinition* rhs);
     void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
                                  MDefinition* lhs, MDefinition* rhs);
-    void visitWasmNeg(MWasmNeg* ins);
-    void visitWasmSelect(MWasmSelect* ins);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerDivI(MDiv* div);
     void lowerModI(MMod* mod);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
     void lowerUrshD(MUrsh* mir);
     void lowerTruncateDToInt32(MTruncateToInt32* ins);
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
-    void visitSimdInsertElement(MSimdInsertElement* ins);
-    void visitSimdExtractElement(MSimdExtractElement* ins);
-    void visitSimdBinaryArith(MSimdBinaryArith* ins);
-    void visitSimdBinarySaturating(MSimdBinarySaturating* ins);
-    void visitSimdSelect(MSimdSelect* ins);
-    void visitSimdSplat(MSimdSplat* ins);
-    void visitSimdSwizzle(MSimdSwizzle* ins);
-    void visitSimdShuffle(MSimdShuffle* ins);
-    void visitSimdGeneralShuffle(MSimdGeneralShuffle* ins);
-    void visitSimdValueX4(MSimdValueX4* ins);
     void lowerCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins,
                                                bool useI386ByteRegisters);
     void lowerAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins,
                                               bool useI386ByteRegisters);
     void lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins,
                                            bool useI386ByteRegisters);
-    void visitCopySign(MCopySign* ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_shared_Lowering_x86_shared_h */
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "jit/x86/Lowering-x86.h"
 
+#include "jit/Lowering.h"
 #include "jit/MIR.h"
 #include "jit/x86/Assembler-x86.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
@@ -45,17 +46,17 @@ LIRGeneratorX86::useByteOpRegisterOrNonD
 
 LDefinition
 LIRGeneratorX86::tempByteOpRegister()
 {
     return tempFixed(eax);
 }
 
 void
-LIRGeneratorX86::visitBox(MBox* box)
+LIRGenerator::visitBox(MBox* box)
 {
     MDefinition* inner = box->getOperand(0);
 
     // If the box wrapped a double, it needs a new register.
     if (IsFloatingPointType(inner->type())) {
         defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0),
                                                  inner->type()), box);
         return;
@@ -85,17 +86,17 @@ LIRGeneratorX86::visitBox(MBox* box)
     // ignored.
     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
     lir->setDef(1, LDefinition::BogusTemp());
     box->setVirtualRegister(vreg);
     add(lir);
 }
 
 void
-LIRGeneratorX86::visitUnbox(MUnbox* unbox)
+LIRGenerator::visitUnbox(MUnbox* unbox)
 {
     MDefinition* inner = unbox->getOperand(0);
 
     if (inner->type() == MIRType::ObjectOrNull) {
         LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
         if (unbox->fallible())
             assignSnapshot(lir, unbox->bailoutKind());
         defineReuseInput(lir, unbox, 0);
@@ -140,17 +141,17 @@ LIRGeneratorX86::visitUnbox(MUnbox* unbo
     // Instead, we create a new virtual register.
     if (reusePayloadReg)
         defineReuseInput(lir, unbox, 0);
     else
         define(lir, unbox);
 }
 
 void
-LIRGeneratorX86::visitReturn(MReturn* ret)
+LIRGenerator::visitReturn(MReturn* ret)
 {
     MDefinition* opd = ret->getOperand(0);
     MOZ_ASSERT(opd->type() == MIRType::Value);
 
     LReturn* ins = new(alloc()) LReturn;
     ins->setOperand(0, LUse(JSReturnReg_Type));
     ins->setOperand(1, LUse(JSReturnReg_Data));
     fillBoxUses(ins, 0, opd);
@@ -245,51 +246,51 @@ LIRGeneratorX86::lowerForMulInt64(LMulI6
     if (needsTemp)
         ins->setTemp(0, temp());
 
     defineInt64Fixed(ins, mir, LInt64Allocation(LAllocation(AnyRegister(edx)),
                                                 LAllocation(AnyRegister(eax))));
 }
 
 void
-LIRGeneratorX86::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
+LIRGenerator::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
     lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ true);
 }
 
 void
-LIRGeneratorX86::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
+LIRGenerator::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
 {
     lowerAtomicExchangeTypedArrayElement(ins, /*useI386ByteRegisters=*/ true);
 }
 
 void
-LIRGeneratorX86::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
+LIRGenerator::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     lowerAtomicTypedArrayElementBinop(ins, /* useI386ByteRegisters = */ true);
 }
 
 void
-LIRGeneratorX86::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
+LIRGenerator::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToDouble* lir = new(alloc()) LWasmUint32ToDouble(useRegisterAtStart(ins->input()), temp());
     define(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
+LIRGenerator::visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
     LWasmUint32ToFloat32* lir = new(alloc()) LWasmUint32ToFloat32(useRegisterAtStart(ins->input()), temp());
     define(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitWasmLoad(MWasmLoad* ins)
+LIRGenerator::visitWasmLoad(MWasmLoad* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* memoryBase = ins->memoryBase();
     MOZ_ASSERT(memoryBase->type() == MIRType::Pointer);
 
     if (ins->access().type() == Scalar::Int64 && ins->access().isAtomic()) {
@@ -329,17 +330,17 @@ LIRGeneratorX86::visitWasmLoad(MWasmLoad
                                                     LAllocation(AnyRegister(eax))));
         return;
     }
 
     defineInt64(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitWasmStore(MWasmStore* ins)
+LIRGenerator::visitWasmStore(MWasmStore* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* memoryBase = ins->memoryBase();
     MOZ_ASSERT(memoryBase->type() == MIRType::Pointer);
 
     if (ins->access().type() == Scalar::Int64 && ins->access().isAtomic()) {
@@ -390,17 +391,17 @@ LIRGeneratorX86::visitWasmStore(MWasmSto
         MOZ_CRASH("unexpected array type");
     }
 
     auto* lir = new(alloc()) LWasmStore(baseAlloc, valueAlloc, useRegisterAtStart(memoryBase));
     add(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
+LIRGenerator::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
     MOZ_ASSERT_IF(ins->needsBoundsCheck(), boundsCheckLimit->type() == MIRType::Int32);
 
     MDefinition* memoryBase = ins->memoryBase();
@@ -415,17 +416,17 @@ LIRGeneratorX86::visitAsmJSLoadHeap(MAsm
                            ? useRegisterAtStart(boundsCheckLimit)
                            : LAllocation();
 
     auto* lir = new(alloc()) LAsmJSLoadHeap(baseAlloc, limitAlloc, useRegisterAtStart(memoryBase));
     define(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
+LIRGenerator::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
     MOZ_ASSERT_IF(ins->needsBoundsCheck(), boundsCheckLimit->type() == MIRType::Int32);
 
     MDefinition* memoryBase = ins->memoryBase();
@@ -464,17 +465,17 @@ LIRGeneratorX86::visitAsmJSStoreHeap(MAs
       case Scalar::Uint8Clamped:
       case Scalar::MaxTypedArrayViewType:
         MOZ_CRASH("unexpected array type");
     }
     add(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
+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()),
@@ -488,17 +489,17 @@ LIRGeneratorX86::visitStoreTypedArrayEle
         break;
       default: MOZ_CRASH("unexpected array type");
     }
 
     add(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
+LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* memoryBase = ins->memoryBase();
     MOZ_ASSERT(memoryBase->type() == MIRType::Pointer);
 
     if (ins->access().type() == Scalar::Int64) {
@@ -536,17 +537,17 @@ LIRGeneratorX86::visitWasmCompareExchang
     LWasmCompareExchangeHeap* lir =
         new(alloc()) LWasmCompareExchangeHeap(useRegister(base), oldval, newval, useRegister(memoryBase));
 
     lir->setAddrTemp(temp());
     defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
 }
 
 void
-LIRGeneratorX86::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
+LIRGenerator::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins)
 {
     MDefinition* memoryBase = ins->memoryBase();
     MOZ_ASSERT(memoryBase->type() == MIRType::Pointer);
 
     if (ins->access().type() == Scalar::Int64) {
         MDefinition* base = ins->base();
         auto* lir = new(alloc()) LWasmAtomicExchangeI64(useRegister(memoryBase),
                                                         useRegister(base),
@@ -567,17 +568,17 @@ LIRGeneratorX86::visitWasmAtomicExchange
     lir->setAddrTemp(temp());
     if (byteSize(ins->access().type()) == 1)
         defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
     else
         define(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
+LIRGenerator::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins)
 {
     MDefinition* base = ins->base();
     MOZ_ASSERT(base->type() == MIRType::Int32);
 
     MDefinition* memoryBase = ins->memoryBase();
     MOZ_ASSERT(memoryBase->type() == MIRType::Pointer);
 
     if (ins->access().type() == Scalar::Int64) {
@@ -718,82 +719,82 @@ LIRGeneratorX86::lowerUModI64(MMod* mod)
 {
     LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64FixedAtStart(mod->lhs(), Register64(eax, ebx)),
                                                     useInt64FixedAtStart(mod->rhs(), Register64(ecx, edx)),
                                                     tempFixed(esi));
     defineReturn(lir, mod);
 }
 
 void
-LIRGeneratorX86::visitSubstr(MSubstr* ins)
+LIRGenerator::visitSubstr(MSubstr* ins)
 {
     // Due to lack of registers on x86, we reuse the string register as
     // temporary. As a result we only need two temporary registers and take a
     // bugos temporary as fifth argument.
     LSubstr* lir = new (alloc()) LSubstr(useRegister(ins->string()),
                                          useRegister(ins->begin()),
                                          useRegister(ins->length()),
                                          temp(),
                                          LDefinition::BogusTemp(),
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGeneratorX86::visitRandom(MRandom* ins)
+LIRGenerator::visitRandom(MRandom* ins)
 {
     LRandom *lir = new(alloc()) LRandom(temp(),
                                         temp(),
                                         temp(),
                                         temp(),
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
-LIRGeneratorX86::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
+LIRGenerator::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
 
     LDefinition temp = tempDouble();
     defineInt64(new(alloc()) LWasmTruncateToInt64(useRegister(opd), temp), ins);
 }
 
 void
-LIRGeneratorX86::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+LIRGenerator::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
     LDefinition maybeTemp = (ins->isUnsigned() &&
                              ((ins->type() == MIRType::Double && AssemblerX86Shared::HasSSE3()) ||
                               ins->type() == MIRType::Float32))
                             ? temp()
                             : LDefinition::BogusTemp();
 
     define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), maybeTemp), ins);
 }
 
 void
-LIRGeneratorX86::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
+LIRGenerator::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     if (ins->isUnsigned()) {
         defineInt64(new(alloc()) LExtendInt32ToInt64(useRegisterAtStart(ins->input())), ins);
     } else {
         LExtendInt32ToInt64* lir =
             new(alloc()) LExtendInt32ToInt64(useFixedAtStart(ins->input(), eax));
         defineInt64Fixed(lir, ins, LInt64Allocation(LAllocation(AnyRegister(edx)),
                                                     LAllocation(AnyRegister(eax))));
     }
 }
 
 void
-LIRGeneratorX86::visitSignExtendInt64(MSignExtendInt64* ins)
+LIRGenerator::visitSignExtendInt64(MSignExtendInt64* ins)
 {
     // Here we'll end up using cdq which requires input and output in (edx,eax).
     LSignExtendInt64* lir =
         new(alloc()) LSignExtendInt64(useInt64FixedAtStart(ins->input(), Register64(edx, eax)));
     defineInt64Fixed(lir, ins, LInt64Allocation(LAllocation(AnyRegister(edx)),
                                                 LAllocation(AnyRegister(eax))));
 }
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -9,22 +9,21 @@
 
 #include "jit/x86-shared/Lowering-x86-shared.h"
 
 namespace js {
 namespace jit {
 
 class LIRGeneratorX86 : public LIRGeneratorX86Shared
 {
-  public:
+  protected:
     LIRGeneratorX86(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorX86Shared(gen, graph, lirGraph)
     { }
 
-  protected:
     // Returns a box allocation with type set to reg1 and payload set to reg2.
     LBoxAllocation useBoxFixed(MDefinition* mir, Register reg1, Register reg2,
                                bool useAtStart = false);
 
     // It's a trap! On x86, the 1-byte store can only use one of
     // {al,bl,cl,dl,ah,bh,ch,dh}. That means if the register allocator
     // gives us one of {edi,esi,ebp,esp}, we're out of luck. (The formatter
     // will assert on us.) Ideally, we'd just ask the register allocator to
@@ -50,45 +49,22 @@ class LIRGeneratorX86 : public LIRGenera
                           MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
     void lowerForMulInt64(LMulI64* ins, MMul* mir, MDefinition* lhs, MDefinition* rhs);
 
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
     void lowerUDivI64(MDiv* div);
     void lowerUModI64(MMod* mod);
 
-  public:
-    void visitBox(MBox* box);
-    void visitUnbox(MUnbox* unbox);
-    void visitReturn(MReturn* ret);
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
-    void visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins);
-    void visitWasmUnsignedToFloat32(MWasmUnsignedToFloat32* ins);
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
-    void visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins);
-    void visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins);
-    void visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins);
-    void visitWasmLoad(MWasmLoad* ins);
-    void visitWasmStore(MWasmStore* ins);
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
-    void visitSubstr(MSubstr* ins);
-    void visitRandom(MRandom* ins);
-    void visitWasmTruncateToInt64(MWasmTruncateToInt64* ins);
-    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
-    void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
-    void visitSignExtendInt64(MSignExtendInt64* ins);
     void lowerPhi(MPhi* phi);
 
+  public:
     static bool allowTypedElementHoleCheck() {
         return true;
     }
-
     static bool allowStaticTypedArrayAccesses() {
         return true;
     }
 };
 
 typedef LIRGeneratorX86 LIRGeneratorSpecific;
 
 } // namespace jit
deleted file mode 100644
--- a/js/xpconnect/crashtests/462926.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script type="text/javascript">
-
-try { document.createTextNode("").getUserData.call(0, 0); } catch(e) { }
-
-</script>
-</head>
-<body>
-</body>
-</html>
--- a/js/xpconnect/crashtests/crashtests.list
+++ b/js/xpconnect/crashtests/crashtests.list
@@ -8,17 +8,16 @@ load 346512-1.xhtml
 load 382133-1.html
 load 386680-1.html
 load 394810-1.html
 load 400349-1.html
 load 403356-1.html
 load 418139-1.svg
 load 420513-1.html
 load 453935-1.html
-load 462926.html
 load 467693-1.html
 load 468552-1.html
 load 471366-1.html
 load 475185-1.html
 load 475291-1.html
 load 503286-1.html
 load 504000-1.html
 load 509075-1.html
--- a/js/xpconnect/tests/chrome/test_weakmaps.xul
+++ b/js/xpconnect/tests/chrome/test_weakmaps.xul
@@ -44,17 +44,23 @@ https://bugzilla.mozilla.org/show_bug.cg
   values reachable only from XPConnect must be marked gray for this to work, and the cycle collector
   must know the proper structure of the heap.
 
   */
   let make_gray_loop = function () {
     let map = new WeakMap;
     let div = document.createElement("div");
     let key = {};
-    div.setUserData("entrain", {m:map, k:key}, null);
+    let obj = {m:map, k:key};
+    div.addEventListener("foo", function() {
+      // The code below doesn't matter (it won't run). Just pull a
+      // reference to obj.
+      obj.k = 1;
+      obj.m = "bar";
+    });
     //div.entrain = {m:map, k:key};  This is not sufficient to cause a leak in Fx9
     map.set(key, div);
     return make_weak_ref(map);
   };
 
   let weakref = make_gray_loop();
 
 
@@ -69,18 +75,25 @@ https://bugzilla.mozilla.org/show_bug.cg
     let dead_dom = document.createElement("div");
     let live_map = new WeakMap;
     let dead_map = new WeakMap;
     let live_key = {};
     let dead_key = {};
 
     // put the live/dead maps/keys into the appropriate DOM elements
     live_dom.basic_unit_tests = {m:live_map, k:live_key};
-    dead_dom.setUserData("hook", {m:dead_map, k:dead_key}, null);
+
+    let obj = {m:dead_map, k:dead_key};
     // dead_dom.hook = {m:dead_map, k:dead_key};
+    dead_dom.addEventListener("foo", function() {
+      // The code below doesn't matter (it won't run). Just pull a
+      // reference to obj.
+      obj.m = 1;
+      obj.k = "2";
+    });
 
     // Create a dead value, and a weak ref to it.
     // The loop keeps dead_dom alive unless the CC is smart enough to kill it.
     let dead_val = {loop:dead_dom};
     basic_weak_ref = make_weak_ref(dead_val);
     basic_map_weak_ref = make_weak_ref(dead_map);
 
     // set up the actual entries.  most will die.
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -427,20 +427,35 @@ static int32_t gMaxRCProcessingTime = -1
 
 struct nsCallbackEventRequest
 {
   nsIReflowCallback* callback;
   nsCallbackEventRequest* next;
 };
 
 // ----------------------------------------------------------------------------
+//
+// NOTE(emilio): It'd be nice for this to assert that our document isn't in the
+// bfcache, but font pref changes don't care about that, and maybe / probably
+// shouldn't.
+#ifdef DEBUG
 #define ASSERT_REFLOW_SCHEDULED_STATE()                                       \
-  NS_ASSERTION(ObservingLayoutFlushes() ==                                    \
-                 GetPresContext()->RefreshDriver()->                          \
-                   IsLayoutFlushObserver(this), "Unexpected state")
+{                                                                             \
+  if (ObservingLayoutFlushes()) {                                             \
+    MOZ_ASSERT(mDocument->GetBFCacheEntry() ||                                \
+               mPresContext->RefreshDriver()->IsLayoutFlushObserver(this),    \
+               "Unexpected state");                                           \
+  } else {                                                                    \
+    MOZ_ASSERT(!mPresContext->RefreshDriver()->IsLayoutFlushObserver(this),   \
+               "Unexpected state");                                           \
+  }                                                                           \
+}
+#else
+#define ASSERT_REFLOW_SCHEDULED_STATE() /* nothing */
+#endif
 
 class nsAutoCauseReflowNotifier
 {
 public:
   explicit nsAutoCauseReflowNotifier(PresShell* aShell)
     : mShell(aShell)
   {
     mShell->WillCauseReflow();
@@ -792,16 +807,17 @@ nsIPresShell::nsIPresShell()
     , mIsFirstPaint(false)
     , mObservesMutationsForPrint(false)
     , mWasLastReflowInterrupted(false)
     , mScrollPositionClampingScrollPortSizeSet(false)
     , mNeedLayoutFlush(true)
     , mNeedStyleFlush(true)
     , mObservingStyleFlushes(false)
     , mObservingLayoutFlushes(false)
+    , mResizeEventPending(false)
     , mNeedThrottledAnimationFlush(true)
     , mPresShellId(0)
     , mFontSizeInflationEmPerLine(0)
     , mFontSizeInflationMinTwips(0)
     , mFontSizeInflationLineThreshold(0)
     , mFontSizeInflationForceEnabled(false)
     , mFontSizeInflationDisabledInMasterProcess(false)
     , mFontSizeInflationEnabled(false)
@@ -829,17 +845,16 @@ PresShell::PresShell()
   , mAPZFocusSequenceNumber(0)
   , mDocumentLoading(false)
   , mIgnoreFrameDestruction(false)
   , mHaveShutDown(false)
   , mLastRootReflowHadUnconstrainedBSize(false)
   , mNoDelayedMouseEvents(false)
   , mNoDelayedKeyEvents(false)
   , mShouldUnsuppressPainting(false)
-  , mResizeEventPending(false)
   , mApproximateFrameVisibilityVisited(false)
   , mNextPaintCompressed(false)
   , mHasCSSBackgroundColor(false)
   , mScaleToResolution(false)
   , mIsLastChromeOnlyEscapeKeyConsumed(false)
   , mHasReceivedPaintMessage(false)
   , mHasHandledUserInput(false)
 {
@@ -1363,20 +1378,17 @@ PresShell::Destroy()
 
   if (mPresContext) {
     rd->CancelPendingAnimationEvents(mPresContext->AnimationEventDispatcher());
   }
 
   // Revoke any pending events.  We need to do this and cancel pending reflows
   // before we destroy the frame manager, since apparently frame destruction
   // sometimes spins the event queue when plug-ins are involved(!).
-  if (mResizeEventPending) {
-    rd->RemoveResizeEventFlushObserver(this);
-  }
-  rd->RemoveLayoutFlushObserver(this);
+  StopObservingRefreshDriver();
 
   if (rd->GetPresContext() == GetPresContext()) {
     rd->RevokeViewManagerFlush();
   }
 
   CancelAllPendingReflows();
   CancelPostedReflowCallbacks();
 
@@ -1409,16 +1421,46 @@ PresShell::Destroy()
     mPresContext->SetLinkHandler(nullptr);
   }
 
   mHaveShutDown = true;
 
   mTouchManager.Destroy();
 }
 
+void
+nsIPresShell::StopObservingRefreshDriver()
+{
+  nsRefreshDriver* rd = mPresContext->RefreshDriver();
+  if (mResizeEventPending) {
+    rd->RemoveResizeEventFlushObserver(this);
+  }
+  if (mObservingLayoutFlushes) {
+    rd->RemoveLayoutFlushObserver(this);
+  }
+  if (mObservingStyleFlushes) {
+    rd->RemoveStyleFlushObserver(this);
+  }
+}
+
+void
+nsIPresShell::StartObservingRefreshDriver()
+{
+  nsRefreshDriver* rd = mPresContext->RefreshDriver();
+  if (mResizeEventPending) {
+    rd->AddResizeEventFlushObserver(this);
+  }
+  if (mObservingLayoutFlushes) {
+    rd->AddLayoutFlushObserver(this);
+  }
+  if (mObservingStyleFlushes) {
+    rd->AddStyleFlushObserver(this);
+  }
+}
+
 nsRefreshDriver*
 nsIPresShell::GetRefreshDriver() const
 {
   return mPresContext ? mPresContext->RefreshDriver() : nullptr;
 }
 
 void
 nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled)
@@ -2050,17 +2092,19 @@ PresShell::ResizeReflowIgnoreOverride(ns
         mPresContext->SetVisibleArea(
           nsRect(0, 0, aWidth, rootFrame->GetRect().height));
       }
     }
   }
 
   if (!mIsDestroying && !mResizeEventPending) {
     mResizeEventPending = true;
-    GetPresContext()->RefreshDriver()->AddResizeEventFlushObserver(this);
+    if (MOZ_LIKELY(!mDocument->GetBFCacheEntry())) {
+      mPresContext->RefreshDriver()->AddResizeEventFlushObserver(this);
+    }
   }
 
   return NS_OK; //XXX this needs to be real. MMP
 }
 
 void
 PresShell::FireResizeEvent()
 {
@@ -9207,26 +9251,32 @@ nsIPresShell::RemovePostRefreshObserver(
   presContext->RefreshDriver()->RemovePostRefreshObserver(aObserver);
   return true;
 }
 
 void
 nsIPresShell::DoObserveStyleFlushes()
 {
   MOZ_ASSERT(!ObservingStyleFlushes());
-  mObservingStyleFlushes =
+  mObservingStyleFlushes = true;
+
+  if (MOZ_LIKELY(!mDocument->GetBFCacheEntry())) {
     mPresContext->RefreshDriver()->AddStyleFlushObserver(this);
+  }
 }
 
 void
 nsIPresShell::DoObserveLayoutFlushes()
 {
   MOZ_ASSERT(!ObservingLayoutFlushes());
-  mObservingLayoutFlushes =
+  mObservingLayoutFlushes = true;
+
+  if (MOZ_LIKELY(!mDocument->GetBFCacheEntry())) {
     mPresContext->RefreshDriver()->AddLayoutFlushObserver(this);
+  }
 }
 
 //------------------------------------------------------
 // End of protected and private methods on the PresShell
 //------------------------------------------------------
 
 //------------------------------------------------------------------
 //-- Delayed event Classes Impls
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -850,18 +850,16 @@ private:
   bool mLastRootReflowHadUnconstrainedBSize : 1;
   bool mNoDelayedMouseEvents : 1;
   bool mNoDelayedKeyEvents : 1;
 
   // Indicates that it is safe to unlock painting once all pending reflows
   // have been processed.
   bool mShouldUnsuppressPainting : 1;
 
-  bool mResizeEventPending : 1;
-
   bool mApproximateFrameVisibilityVisited : 1;
 
   bool mNextPaintCompressed : 1;
 
   bool mHasCSSBackgroundColor : 1;
 
   // Whether content should be scaled by the resolution amount. If this is
   // not set, a transform that scales by the inverse of the resolution is
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -8938,24 +8938,16 @@ nsCSSFrameConstructor::WillDestroyFrameT
   mCounterManager.Dump();
 #endif
 
   mIsDestroyingFrameTree = true;
 
   // Prevent frame tree destruction from being O(N^2)
   mQuoteList.Clear();
   mCounterManager.Clear();
-
-  // Remove our presshell as a style flush observer.  But leave
-  // RestyleManager::mObservingRefreshDriver true so we don't readd to
-  // it even if someone tries to post restyle events on us from this
-  // point on for some reason.
-  mPresShell->GetPresContext()->RefreshDriver()->
-    RemoveStyleFlushObserver(mPresShell);
-
   nsFrameManager::Destroy();
 }
 
 //STATIC
 
 // XXXbz I'd really like this method to go away. Once we have inline-block and
 // I can just use that for sized broken images, that can happen, maybe.
 void
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -610,16 +610,33 @@ public:
            mInFlush;
   }
 
   inline void EnsureStyleFlush();
   inline void SetNeedStyleFlush();
   inline void SetNeedLayoutFlush();
   inline void SetNeedThrottledAnimationFlush();
 
+  // Removes ourself from the list of layout / style / and resize refresh driver
+  // observers.
+  //
+  // Right now this is only used for documents in the BFCache, so if you want to
+  // use this for anything else you need to ensure we don't end up in those
+  // lists after calling this, but before calling StartObservingRefreshDriver
+  // again.
+  //
+  // That is handled by the mDocument->GetBFCacheEntry checks in
+  // DoObserve*Flushes functions, though that could conceivably become a boolean
+  // member in the shell if needed.
+  //
+  // Callers are responsible of manually calling StartObservingRefreshDriver
+  // again.
+  void StopObservingRefreshDriver();
+  void StartObservingRefreshDriver();
+
   bool ObservingStyleFlushes() const { return mObservingStyleFlushes; }
   bool ObservingLayoutFlushes() const { return mObservingLayoutFlushes; }
 
   void ObserveStyleFlushes()
   {
     if (!ObservingStyleFlushes())
       DoObserveStyleFlushes();
   }
@@ -1774,16 +1791,18 @@ protected:
   bool mObservingStyleFlushes: 1;
 
   // True if we're observing the refresh driver for layout flushes, that is, if
   // we have a reflow scheduled.
   //
   // Guaranteed to be false if mReflowContinueTimer is non-null.
   bool mObservingLayoutFlushes: 1;
 
+  bool mResizeEventPending : 1;
+
   // True if there are throttled animations that would be processed when
   // performing a flush with mFlushAnimations == true.
   bool mNeedThrottledAnimationFlush : 1;
 
   uint32_t                  mPresShellId;
 
   static nsIContent*        gKeyDownTarget;
 
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -154,52 +154,56 @@ public:
   bool AddImageRequest(imgIRequest* aRequest);
   void RemoveImageRequest(imgIRequest* aRequest);
 
   /**
    * Add / remove presshells which have pending resize event.
    */
   void AddResizeEventFlushObserver(nsIPresShell* aShell)
   {
-    NS_ASSERTION(!mResizeEventFlushObservers.Contains(aShell),
-                 "Double-adding resize event flush observer");
+    MOZ_DIAGNOSTIC_ASSERT(!mResizeEventFlushObservers.Contains(aShell),
+                          "Double-adding resize event flush observer");
     mResizeEventFlushObservers.AppendElement(aShell);
     EnsureTimerStarted();
   }
 
   void RemoveResizeEventFlushObserver(nsIPresShell* aShell)
   {
     mResizeEventFlushObservers.RemoveElement(aShell);
   }
 
   /**
    * Add / remove presshells that we should flush style and layout on
    */
-  bool AddStyleFlushObserver(nsIPresShell* aShell) {
-    NS_ASSERTION(!mStyleFlushObservers.Contains(aShell),
-                 "Double-adding style flush observer");
-    bool appended = mStyleFlushObservers.AppendElement(aShell) != nullptr;
+  void AddStyleFlushObserver(nsIPresShell* aShell)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(!mStyleFlushObservers.Contains(aShell),
+                          "Double-adding style flush observer");
+    mStyleFlushObservers.AppendElement(aShell);
     EnsureTimerStarted();
+  }
 
-    return appended;
-  }
-  void RemoveStyleFlushObserver(nsIPresShell* aShell) {
+  void RemoveStyleFlushObserver(nsIPresShell* aShell)
+  {
     mStyleFlushObservers.RemoveElement(aShell);
   }
-  bool AddLayoutFlushObserver(nsIPresShell* aShell) {
-    NS_ASSERTION(!IsLayoutFlushObserver(aShell),
-                 "Double-adding layout flush observer");
-    bool appended = mLayoutFlushObservers.AppendElement(aShell) != nullptr;
+  void AddLayoutFlushObserver(nsIPresShell* aShell)
+  {
+    MOZ_DIAGNOSTIC_ASSERT(!IsLayoutFlushObserver(aShell),
+                          "Double-adding layout flush observer");
+    mLayoutFlushObservers.AppendElement(aShell);
     EnsureTimerStarted();
-    return appended;
   }
-  void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
+  void RemoveLayoutFlushObserver(nsIPresShell* aShell)
+  {
     mLayoutFlushObservers.RemoveElement(aShell);
   }
-  bool IsLayoutFlushObserver(nsIPresShell* aShell) {
+
+  bool IsLayoutFlushObserver(nsIPresShell* aShell)
+  {
     return mLayoutFlushObservers.Contains(aShell);
   }
 
   /**
    * "Early Runner" runnables will be called as the first step when refresh
    * driver tick is triggered. Runners shouldn't keep other objects alive,
    * since it isn't guaranteed they will ever get called.
    */
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -21,17 +21,16 @@
 #include "nsIPrincipal.h"
 #include "nsIFileURL.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Preferences.h"
 #include "nsITabChild.h"
 #include "private/pprio.h"
 #include "nsInputStreamPump.h"
-#include "nsThreadUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 // the entry for a directory will either be empty (in the case of the
 // top-level directory) or will end with a slash
@@ -194,31 +193,27 @@ nsJARInputThunk::IsNonBlocking(bool *non
 
 nsJARChannel::nsJARChannel()
     : mOpened(false)
     , mContentDisposition(0)
     , mContentLength(-1)
     , mLoadFlags(LOAD_NORMAL)
     , mStatus(NS_OK)
     , mIsPending(false)
-    , mEnableOMT(true)
-    , mPendingEvent()
     , mIsUnsafe(true)
     , mBlockRemoteFiles(false)
 {
-    LOG(("nsJARChannel::nsJARChannel [this=%p]\n", this));
     mBlockRemoteFiles = Preferences::GetBool("network.jar.block-remote-files", false);
 
     // hold an owning reference to the jar handler
     mJarHandler = gJarHandler;
 }
 
 nsJARChannel::~nsJARChannel()
 {
-    LOG(("nsJARChannel::~nsJARChannel [this=%p]\n", this));
     NS_ReleaseOnMainThreadSystemGroup("nsJARChannel::mLoadInfo",
                                       mLoadInfo.forget());
 }
 
 NS_IMPL_ISUPPORTS_INHERITED(nsJARChannel,
                             nsHashPropertyBag,
                             nsIRequest,
                             nsIChannel,
@@ -226,24 +221,17 @@ NS_IMPL_ISUPPORTS_INHERITED(nsJARChannel
                             nsIRequestObserver,
                             nsIThreadRetargetableRequest,
                             nsIThreadRetargetableStreamListener,
                             nsIJARChannel)
 
 nsresult
 nsJARChannel::Init(nsIURI *uri)
 {
-    LOG(("nsJARChannel::Init [this=%p]\n", this));
     nsresult rv;
-
-    mWorker = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
-    if (NS_FAILED(rv)) {
-        return rv;
-    }
-
     mJarURI = do_QueryInterface(uri, &rv);
     if (NS_FAILED(rv))
         return rv;
 
     mOriginalURI = mJarURI;
 
     // Prevent loading jar:javascript URIs (see bug 290982).
     nsCOMPtr<nsIURI> innerURI;
@@ -261,33 +249,32 @@ nsJARChannel::Init(nsIURI *uri)
 
     mJarURI->GetSpec(mSpec);
     return rv;
 }
 
 nsresult
 nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resultInput)
 {
-    LOG(("nsJARChannel::CreateJarInput [this=%p]\n", this));
     MOZ_ASSERT(resultInput);
     MOZ_ASSERT(mJarFile || mTempMem);
 
     // important to pass a clone of the file since the nsIFile impl is not
     // necessarily MT-safe
     nsCOMPtr<nsIFile> clonedFile;
     nsresult rv = NS_OK;
     if (mJarFile) {
         rv = mJarFile->Clone(getter_AddRefs(clonedFile));
         if (NS_FAILED(rv))
             return rv;
     }
 
     nsCOMPtr<nsIZipReader> reader;
     if (mPreCachedJarReader) {
-        reader = mPreCachedJarReader;
+      reader = mPreCachedJarReader;
     } else if (jarCache) {
         MOZ_ASSERT(mJarFile);
         if (mInnerJarEntry.IsEmpty())
             rv = jarCache->GetZip(clonedFile, getter_AddRefs(reader));
         else
             rv = jarCache->GetInnerZip(clonedFile, mInnerJarEntry,
                                        getter_AddRefs(reader));
     } else {
@@ -314,32 +301,33 @@ nsJARChannel::CreateJarInput(nsIZipReade
 
             rv = reader->OpenInner(outerReader, mInnerJarEntry);
         }
     }
     if (NS_FAILED(rv))
         return rv;
 
     RefPtr<nsJARInputThunk> input = new nsJARInputThunk(reader,
-                                                        mJarURI,
-                                                        mJarEntry,
-                                                        jarCache != nullptr);
+                                                          mJarURI,
+                                                          mJarEntry,
+                                                          jarCache != nullptr
+                                                          );
     rv = input->Init();
     if (NS_FAILED(rv))
         return rv;
 
     // Make GetContentLength meaningful
     mContentLength = input->GetContentLength();
 
     input.forget(resultInput);
     return NS_OK;
 }
 
 nsresult
-nsJARChannel::LookupFile()
+nsJARChannel::LookupFile(bool aAllowAsync)
 {
     LOG(("nsJARChannel::LookupFile [this=%p %s]\n", this, mSpec.get()));
 
     if (mJarFile)
         return NS_OK;
 
     nsresult rv;
 
@@ -385,245 +373,34 @@ nsJARChannel::LookupFile()
             }
         }
     }
 
     return rv;
 }
 
 nsresult
-CreateLocalJarInput(nsIZipReaderCache* aJarCache,
-                    nsIFile* aFile,
-                    const nsACString& aInnerJarEntry,
-                    nsIJARURI* aJarURI,
-                    const nsACString& aJarEntry,
-                    nsJARInputThunk** aResultInput)
-{
-    LOG(("nsJARChannel::CreateLocalJarInput [aJarCache=%p, %s, %s]\n",
-         aJarCache,
-         PromiseFlatCString(aInnerJarEntry).get(),
-         PromiseFlatCString(aJarEntry).get()));
-
-    MOZ_ASSERT(!NS_IsMainThread());
-    MOZ_ASSERT(aJarCache);
-    MOZ_ASSERT(aResultInput);
-
-    nsresult rv;
-
-    nsCOMPtr<nsIZipReader> reader;
-    if (aInnerJarEntry.IsEmpty()) {
-        rv = aJarCache->GetZip(aFile, getter_AddRefs(reader));
-    } else {
-        rv = aJarCache->GetInnerZip(aFile,
-                                    aInnerJarEntry,
-                                    getter_AddRefs(reader));
-    }
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-    }
-
-    RefPtr<nsJARInputThunk> input = new nsJARInputThunk(reader,
-                                                        aJarURI,
-                                                        aJarEntry,
-                                                        aJarCache != nullptr);
-    rv = input->Init();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-    }
-
-    input.forget(aResultInput);
-    return NS_OK;
-}
-
-nsresult
 nsJARChannel::OpenLocalFile()
 {
-    LOG(("nsJARChannel::OpenLocalFile [this=%p]\n", this));
-
-    MOZ_ASSERT(NS_IsMainThread());
-
-    MOZ_ASSERT(mWorker);
     MOZ_ASSERT(mIsPending);
-    MOZ_ASSERT(mJarFile);
 
     // Local files are always considered safe.
     mIsUnsafe = false;
 
-    nsresult rv;
-
-    // Set mLoadGroup and mOpened before AsyncOpen return, and set back if
-    // if failed when callback.
-    if (mLoadGroup) {
-        mLoadGroup->AddRequest(this, nullptr);
-    }
-    mOpened = true;
-
-    if (mPreCachedJarReader || !mEnableOMT) {
-        RefPtr<nsJARInputThunk> input;
-        rv = CreateJarInput(gJarHandler->JarCache(),
-                            getter_AddRefs(input));
-        if (NS_WARN_IF(NS_FAILED(rv))) {
-            return OnOpenLocalFileComplete(rv, true);
-        }
-        return ContinueOpenLocalFile(input, true);
-    }
-
-
-    nsCOMPtr<nsIZipReaderCache> jarCache = gJarHandler->JarCache();
-    if (NS_WARN_IF(!jarCache)) {
-        return NS_ERROR_UNEXPECTED;
-    }
-
-    nsCOMPtr<nsIFile> clonedFile;
-    rv = mJarFile->Clone(getter_AddRefs(clonedFile));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-    }
-
-    // clone mJarURI
-    nsCOMPtr<nsIURI> clonedURI;
-    rv = mJarURI->Clone(getter_AddRefs(clonedURI));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-    }
-    nsCOMPtr<nsIJARURI> clonedJarURI = do_QueryInterface(clonedURI, &rv);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
+    RefPtr<nsJARInputThunk> input;
+    nsresult rv = CreateJarInput(gJarHandler->JarCache(),
+                                 getter_AddRefs(input));
+    if (NS_SUCCEEDED(rv)) {
+        // Create input stream pump and call AsyncRead as a block.
+        rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input.forget());
+        if (NS_SUCCEEDED(rv))
+            rv = mPump->AsyncRead(this, nullptr);
     }
 
-    nsAutoCString jarEntry(mJarEntry);
-    nsAutoCString innerJarEntry(mInnerJarEntry);
-
-    RefPtr<nsJARChannel> self = this;
-    return mWorker->Dispatch(
-            NS_NewRunnableFunction("nsJARChannel::OpenLocalFile",
-                                   [self,
-                                   jarCache,
-                                   clonedFile,
-                                   clonedJarURI,
-                                   jarEntry,
-                                   innerJarEntry] () mutable {
-
-        RefPtr<nsJARInputThunk> input;
-        nsresult rv = CreateLocalJarInput(jarCache,
-                                          clonedFile,
-                                          innerJarEntry,
-                                          clonedJarURI,
-                                          jarEntry,
-                                          getter_AddRefs(input));
-
-        NS_ReleaseOnMainThreadSystemGroup("nsJARChannel::clonedJarURI",
-                                          clonedJarURI.forget());
-
-        nsCOMPtr<nsIRunnable> target;
-        if (NS_SUCCEEDED(rv)) {
-            target = NewRunnableMethod<RefPtr<nsJARInputThunk>, bool>(
-                "nsJARChannel::ContinueOpenLocalFile",
-                self,
-                &nsJARChannel::ContinueOpenLocalFile,
-                input,
-                false);
-        } else {
-            target = NewRunnableMethod<nsresult, bool>(
-                "nsJARChannel::OnOpenLocalFileComplete",
-                self,
-                &nsJARChannel::OnOpenLocalFileComplete,
-                rv,
-                false);
-        }
-
-        // nsJARChannel must be release on main thread, and sometimes
-        // this still hold nsJARChannel after dispatched.
-        self = nullptr;
-
-        NS_DispatchToMainThread(target.forget());
-    }));
-}
-
-nsresult
-nsJARChannel::ContinueOpenLocalFile(nsJARInputThunk* aInput, bool aIsSyncCall)
-{
-    LOG(("nsJARChannel::ContinueOpenLocalFile [this=%p %p]\n", this, aInput));
-
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mIsPending);
-
-    // Make GetContentLength meaningful
-    mContentLength = aInput->GetContentLength();
-
-    nsresult rv;
-    RefPtr<nsJARInputThunk> input = aInput;
-    // Create input stream pump and call AsyncRead as a block.
-    rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input.forget());
-    if (NS_SUCCEEDED(rv)) {
-        rv = mPump->AsyncRead(this, nullptr);
-    }
-
-    if (NS_SUCCEEDED(rv)) {
-        rv = CheckPendingEvents();
-    }
-
-    return OnOpenLocalFileComplete(rv, aIsSyncCall);
-}
-
-nsresult
-nsJARChannel::OnOpenLocalFileComplete(nsresult aResult, bool aIsSyncCall)
-{
-    LOG(("nsJARChannel::OnOpenLocalFileComplete [this=%p %08x]\n",
-         this,
-         static_cast<uint32_t>(aResult)));
-
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mIsPending);
-
-    if (NS_FAILED(aResult)) {
-        if (!aIsSyncCall) {
-            NotifyError(aResult);
-        }
-
-        if (mLoadGroup) {
-            mLoadGroup->RemoveRequest(this, nullptr, aResult);
-        }
-
-        mOpened = false;
-        mIsPending = false;
-        mListenerContext = nullptr;
-        mListener = nullptr;
-        mCallbacks = nullptr;
-        mProgressSink = nullptr;
-
-        return aResult;
-    }
-
-    return NS_OK;
-}
-
-nsresult nsJARChannel::CheckPendingEvents()
-{
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mIsPending);
-    MOZ_ASSERT(mPump);
-
-    nsresult rv;
-
-    auto suspendCount = mPendingEvent.suspendCount;
-    while (suspendCount--) {
-        if (NS_WARN_IF(NS_FAILED(rv = mPump->Suspend()))) {
-            return rv;
-        }
-    }
-
-    if (mPendingEvent.isCanceled) {
-        if (NS_WARN_IF(NS_FAILED(rv = mPump->Cancel(mStatus)))) {
-            return rv;
-        }
-        mPendingEvent.isCanceled = false;
-    }
-
-    return NS_OK;
+    return rv;
 }
 
 void
 nsJARChannel::NotifyError(nsresult aError)
 {
     MOZ_ASSERT(NS_FAILED(aError));
 
     mStatus = aError;
@@ -667,51 +444,40 @@ nsJARChannel::GetStatus(nsresult *status
         *status = mStatus;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::Cancel(nsresult status)
 {
     mStatus = status;
-    if (mPump) {
+    if (mPump)
         return mPump->Cancel(status);
-    }
 
-    if (mIsPending) {
-        mPendingEvent.isCanceled = true;
-    }
-
+    NS_ASSERTION(!mIsPending, "need to implement cancel when downloading");
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::Suspend()
 {
-    ++mPendingEvent.suspendCount;
+    if (mPump)
+        return mPump->Suspend();
 
-    if (mPump) {
-        return mPump->Suspend();
-    }
-
+    NS_ASSERTION(!mIsPending, "need to implement suspend when downloading");
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::Resume()
 {
-    if (NS_WARN_IF(mPendingEvent.suspendCount == 0)) {
-        return NS_ERROR_UNEXPECTED;
-    }
-    --mPendingEvent.suspendCount;
+    if (mPump)
+        return mPump->Resume();
 
-    if (mPump) {
-        return mPump->Resume();
-    }
-
+    NS_ASSERTION(!mIsPending, "need to implement resume when downloading");
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
 {
     *aLoadFlags = mLoadFlags;
     return NS_OK;
@@ -955,17 +721,17 @@ nsJARChannel::Open(nsIInputStream **stre
     LOG(("nsJARChannel::Open [this=%p]\n", this));
 
     NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
 
     mJarFile = nullptr;
     mIsUnsafe = true;
 
-    nsresult rv = LookupFile();
+    nsresult rv = LookupFile(false);
     if (NS_FAILED(rv))
         return rv;
 
     // If mJarInput was not set by LookupFile, the JAR is a remote jar.
     if (!mJarFile) {
         NS_NOTREACHED("need sync downloader");
         return NS_ERROR_NOT_IMPLEMENTED;
     }
@@ -980,27 +746,25 @@ nsJARChannel::Open(nsIInputStream **stre
     // local files are always considered safe
     mIsUnsafe = false;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::Open2(nsIInputStream** aStream)
 {
-    LOG(("nsJARChannel::Open2 [this=%p]\n", this));
     nsCOMPtr<nsIStreamListener> listener;
     nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
     NS_ENSURE_SUCCESS(rv, rv);
     return Open(aStream);
 }
 
 NS_IMETHODIMP
 nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
 {
-    LOG(("nsJARChannel::AsyncOpen [this=%p]\n", this));
     MOZ_ASSERT(!mLoadInfo ||
                mLoadInfo->GetSecurityMode() == 0 ||
                mLoadInfo->GetInitialSecurityCheckDone() ||
                (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
                 nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
                "security flags in loadInfo but asyncOpen2() not called");
 
     LOG(("nsJARChannel::AsyncOpen [this=%p]\n", this));
@@ -1014,17 +778,17 @@ nsJARChannel::AsyncOpen(nsIStreamListene
 
     // Initialize mProgressSink
     NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
 
     mListener = listener;
     mListenerContext = ctx;
     mIsPending = true;
 
-    nsresult rv = LookupFile();
+    nsresult rv = LookupFile(true);
     if (NS_FAILED(rv)) {
         mIsPending = false;
         mListenerContext = nullptr;
         mListener = nullptr;
         mCallbacks = nullptr;
         mProgressSink = nullptr;
         return rv;
     }
@@ -1065,46 +829,41 @@ nsJARChannel::AsyncOpen(nsIStreamListene
             return rv;
         }
         if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
             rv = channel->AsyncOpen2(downloader);
         }
         else {
             rv = channel->AsyncOpen(downloader, nullptr);
         }
-
     }
     else {
         rv = OpenLocalFile();
-        if (NS_SUCCEEDED(rv)) {
-            return NS_OK;
-        }
     }
 
     if (NS_FAILED(rv)) {
         mIsPending = false;
         mListenerContext = nullptr;
         mListener = nullptr;
         mCallbacks = nullptr;
         mProgressSink = nullptr;
         return rv;
     }
 
     if (mLoadGroup)
         mLoadGroup->AddRequest(this, nullptr);
 
     mOpened = true;
-    LOG(("nsJARChannel::AsyncOpen [this=%p] 8\n", this));
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::AsyncOpen2(nsIStreamListener *aListener)
 {
-    LOG(("nsJARChannel::AsyncOpen2 [this=%p]\n", this));
   nsCOMPtr<nsIStreamListener> listener = aListener;
   nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
   if (NS_FAILED(rv)) {
       mIsPending = false;
       mListenerContext = nullptr;
       mListener = nullptr;
       mCallbacks = nullptr;
       mProgressSink = nullptr;
@@ -1190,17 +949,17 @@ nsJARChannel::EnsureCached(bool *aIsCach
 
     *aIsCached = true;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry)
 {
-    nsresult rv = LookupFile();
+    nsresult rv = LookupFile(false);
     if (NS_FAILED(rv))
         return rv;
 
     if (!mJarFile)
         return NS_ERROR_NOT_AVAILABLE;
 
     nsCOMPtr<nsIZipReader> reader;
     rv = gJarHandler->JarCache()->GetZip(mJarFile, getter_AddRefs(reader));
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsJARChannel_h__
 #define nsJARChannel_h__
 
 #include "mozilla/net/MemoryDownloader.h"
 #include "nsIJARChannel.h"
 #include "nsIJARURI.h"
-#include "nsIEventTarget.h"
 #include "nsIInputStreamPump.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIProgressEventSink.h"
 #include "nsIStreamListener.h"
 #include "nsIZipReader.h"
 #include "nsILoadGroup.h"
 #include "nsILoadInfo.h"
 #include "nsIThreadRetargetableRequest.h"
@@ -54,21 +53,18 @@ public:
     nsresult Init(nsIURI *uri);
 
     void SetFile(nsIFile *file);
 
 private:
     virtual ~nsJARChannel();
 
     nsresult CreateJarInput(nsIZipReaderCache *, nsJARInputThunk **);
-    nsresult LookupFile();
+    nsresult LookupFile(bool aAllowAsync);
     nsresult OpenLocalFile();
-    nsresult ContinueOpenLocalFile(nsJARInputThunk* aInput, bool aIsSyncCall);
-    nsresult OnOpenLocalFileComplete(nsresult aResult, bool aIsSyncCall);
-    nsresult CheckPendingEvents();
     void NotifyError(nsresult aError);
     void FireOnProgress(uint64_t aProgress);
     virtual void OnDownloadComplete(mozilla::net::MemoryDownloader* aDownloader,
                                     nsIRequest* aRequest,
                                     nsISupports* aCtxt,
                                     nsresult aStatus,
                                     mozilla::net::MemoryDownloader::Data aData)
         override;
@@ -92,39 +88,28 @@ private:
     nsCString                       mContentCharset;
     nsCString                       mContentDispositionHeader;
     /* mContentDisposition is uninitialized if mContentDispositionHeader is
      * empty */
     uint32_t                        mContentDisposition;
     int64_t                         mContentLength;
     uint32_t                        mLoadFlags;
     nsresult                        mStatus;
-    bool                            mIsPending; // the AsyncOpen is in progress.
-
-    bool                            mEnableOMT;
-    // |Cancel()|, |Suspend()|, and |Resume()| might be called during AsyncOpen.
-    struct {
-        bool isCanceled;
-        uint32_t suspendCount;
-    }                               mPendingEvent;
-
+    bool                            mIsPending;
     bool                            mIsUnsafe;
 
     mozilla::net::MemoryDownloader::Data mTempMem;
     nsCOMPtr<nsIInputStreamPump>    mPump;
     // mRequest is only non-null during OnStartRequest, so we'll have a pointer
     // to the request if we get called back via RetargetDeliveryTo.
     nsCOMPtr<nsIRequest>            mRequest;
     nsCOMPtr<nsIFile>               mJarFile;
     nsCOMPtr<nsIFile>               mJarFileOverride;
     nsCOMPtr<nsIZipReader>          mPreCachedJarReader;
     nsCOMPtr<nsIURI>                mJarBaseURI;
     nsCString                       mJarEntry;
     nsCString                       mInnerJarEntry;
 
-    // use StreamTransportService as background thread
-    nsCOMPtr<nsIEventTarget>        mWorker;
-
     // True if this channel should not download any remote files.
     bool                            mBlockRemoteFiles;
 };
 
 #endif // nsJARChannel_h__
--- a/security/manager/ssl/StaticHPKPins.h
+++ b/security/manager/ssl/StaticHPKPins.h
@@ -1158,9 +1158,9 @@ static const TransportSecurityPreload kP
   { "za.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
   { "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
 };
 
 // Pinning Preload List Length = 485;
 
 static const int32_t kUnknownId = -1;
 
-static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1529697230601000);
+static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1529784288005000);
--- a/security/manager/ssl/nsSTSPreloadList.errors
+++ b/security/manager/ssl/nsSTSPreloadList.errors
@@ -24,20 +24,22 @@ 249cq.com: could not connect to host
 24ip.fr: could not connect to host
 256k.me: could not connect to host
 2b3b.com: could not connect to host
 2bitout.com: could not connect to host
 2fl.me: could not connect to host
 2gen.com: could not connect to host
 330.net: could not connect to host
 360ds.co.in: could not connect to host
+360woodworking.com: could not connect to host
 38888msc.com: could not connect to host
 38blog.com: could not connect to host
 3dm.audio: could not connect to host
 3vlnaeet.cz: could not connect to host
+404.guide: could not connect to host
 41844.de: could not connect to host
 42t.ru: could not connect to host
 439191.com: could not connect to host
 47tech.com: could not connect to host
 4baby.com.br: could not connect to host
 4d2.xyz: could not connect to host
 4host.ch: could not connect to host
 4loc.us: could not connect to host
@@ -65,26 +67,28 @@ 91-freedom.com: could not connect to hos
 99buffets.com: could not connect to host
 a-ix.net: could not connect to host
 aaron.xin: could not connect to host
 abi-fvs.de: could not connect to host
 abigailstark.com: could not connect to host
 abilma.com: could not connect to host
 abloop.com: could not connect to host
 abolition.co: could not connect to host
+abpis.hr: could not connect to host
 abstractbarista.com: could not connect to host
 abstractbarista.net: could not connect to host
 ac.milan.it: could not connect to host
 acat.io: could not connect to host
 accolade.com.br: could not connect to host
 accwing.com: could not connect to host
 acgaudio.com: could not connect to host
 achterhoekseveiligheidsbeurs.nl: could not connect to host
 acpinformatique.fr: could not connect to host
 acrossgw.com: could not connect to host
+activeclearweb.com: could not connect to host
 activitesaintnicaise.org: could not connect to host
 ad-disruptio.fr: could not connect to host
 adamcoffee.net: could not connect to host
 adamdixon.co.uk: could not connect to host
 adec-emsa.ae: could not connect to host
 adrianajewelry.my: could not connect to host
 adult.properties: could not connect to host
 advaithnikhi.ml: could not connect to host
@@ -100,23 +104,21 @@ agingstop.net: could not connect to host
 agoravm.tk: could not connect to host
 agowa.eu: could not connect to host
 agowa338.de: could not connect to host
 agrilinks.org: could not connect to host
 ahelos.tk: could not connect to host
 ahlz.sk: could not connect to host
 aikenorganics.com: could not connect to host
 aim-consultants.com: could not connect to host
-aimrom.org: could not connect to host
 airclass.com: could not connect to host
 ajetaci.cz: could not connect to host
 akhilindurti.com: could not connect to host
 akiba-server.info: could not connect to host
 akita-stream.com: could not connect to host
-akoch.net: could not connect to host
 akoww.de: could not connect to host
 akul.co.in: could not connect to host
 al-f.net: could not connect to host
 alasta.info: could not connect to host
 alauda-home.de: could not connect to host
 albertify.xyz: could not connect to host
 alcatraz.online: could not connect to host
 alexandernorth.ch: could not connect to host
@@ -132,41 +134,43 @@ alloutatl.com: could not connect to host
 allscammers.exposed: could not connect to host
 allthingsfpl.com: could not connect to host
 alocato.com: could not connect to host
 alohapartyevents.co.uk: could not connect to host
 alpe-d-or.dyn-o-saur.com: could not connect to host
 alphabrock.cn: could not connect to host
 altahrim.net: could not connect to host
 altered.network: could not connect to host
+amazingbouncycastles.co.uk: could not connect to host
 amdouglas.uk: could not connect to host
 ameho.me: could not connect to host
 americandistribuidora.com: could not connect to host
 amilum.org: could not connect to host
 amua.fr: could not connect to host
 amunoz.org: could not connect to host
 anadoluefessk.org: could not connect to host
 analyzemyfriends.com: could not connect to host
 anastasia-shamara.ru: could not connect to host
 andreas-kluge.eu: could not connect to host
 andreaskluge.eu: could not connect to host
 andrei-coman.com: could not connect to host
-andrespaz.com: could not connect to host
 andrewdaws.co: could not connect to host
 andrewdaws.info: could not connect to host
 andrewdaws.me: could not connect to host
 andrewdaws.tv: could not connect to host
 andrewrdaws.com: could not connect to host
 andronika.net: could not connect to host
 anecuni-club.com: could not connect to host
 anecuni-rec.com: could not connect to host
 angrydragonproductions.com: could not connect to host
 anitube-nocookie.ch: could not connect to host
 anivar.net: could not connect to host
 annetaan.fi: could not connect to host
+ansgar-sonntag.de: could not connect to host
+ansgarsonntag.de: could not connect to host
 antimatiere.space: could not connect to host
 anyways.at: could not connect to host
 aojiao.org: could not connect to host
 apkoyunlar.club: could not connect to host
 appdrinks.com: could not connect to host
 apple.ax: could not connect to host
 apps4all.sytes.net: could not connect to host
 apptoutou.com: could not connect to host
@@ -193,17 +197,16 @@ asphaltfruehling.de: could not connect t
 asphyxia.su: could not connect to host
 aspisdata.com: could not connect to host
 asral7.com: could not connect to host
 assdecoeur.org: could not connect to host
 assindia.nl: could not connect to host
 asthon.cn: could not connect to host
 astrath.net: could not connect to host
 astrea-voetbal-groningen.nl: could not connect to host