Merge mozilla-central to inbound. a=merge CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 02 Apr 2019 18:50:37 +0300
changeset 467570 a6c6359636f707359a67830c6fd1dc227543689b
parent 467521 5da02ff0be569ab1c60033ab7eaeb1e8941fd909 (current diff)
parent 467569 92d1c344e7c53af9b8ad8a4192d93478f71ba5cf (diff)
child 467571 69736a7748c5299459dfb8121d8b2bf42a1ea410
push id112633
push usercbrindusan@mozilla.com
push dateTue, 02 Apr 2019 15:52:18 +0000
treeherdermozilla-inbound@a6c6359636f7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.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 inbound. a=merge CLOSED TREE
build/build-clang/rename_gcov_flush_.patch
xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s
xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s
xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s
xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_solaris_SUNW.s
xpcom/reflect/xptcall/md/unix/xptcinvoke_sparcv9_solaris.cpp
xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_solaris.cpp
xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_solaris.cpp
xpcom/reflect/xptcall/md/unix/xptcstubs_asm_sparcv9_solaris.s
xpcom/reflect/xptcall/md/unix/xptcstubs_asm_x86_64_solaris_SUNW.s
xpcom/reflect/xptcall/md/unix/xptcstubs_asm_x86_solaris_SUNW.s
xpcom/reflect/xptcall/md/unix/xptcstubs_sparcv9_solaris.cpp
xpcom/reflect/xptcall/md/unix/xptcstubs_x86_64_solaris.cpp
xpcom/reflect/xptcall/md/unix/xptcstubs_x86_solaris.cpp
--- a/browser/actors/ContextMenuChild.jsm
+++ b/browser/actors/ContextMenuChild.jsm
@@ -27,16 +27,21 @@ XPCOMUtils.defineLazyModuleGetters(this,
 });
 
 XPCOMUtils.defineLazyGetter(this, "PageMenuChild", () => {
   let tmp = {};
   ChromeUtils.import("resource://gre/modules/PageMenu.jsm", tmp);
   return new tmp.PageMenuChild();
 });
 
+XPCOMUtils.defineLazyGetter(this, "ReferrerInfo", () =>
+  Components.Constructor("@mozilla.org/referrer-info;1",
+                         "nsIReferrerInfo",
+                         "init"));
+
 const messageListeners = {
   "ContextMenu:BookmarkFrame": function(aMessage) {
     let frame = this.getTarget(aMessage).ownerDocument;
 
     this.mm.sendAsyncMessage("ContextMenu:BookmarkFrame:Result",
                              { title: frame.title });
   },
 
@@ -597,16 +602,25 @@ class ContextMenuChild extends ActorChil
       let mainWin = browser.ownerGlobal;
 
       data.documentURIObject = doc.documentURIObject;
       data.disableSetDesktopBackground = data.disableSetDesktopBg;
       delete data.disableSetDesktopBg;
 
       data.context.targetAsCPOW = targetAsCPOW;
 
+      data.referrerInfo = new ReferrerInfo(
+        referrerPolicy,
+        !context.linkHasNoReferrer,
+        data.documentURIObject);
+      data.frameReferrerInfo = new ReferrerInfo(
+        referrerPolicy,
+        !context.linkHasNoReferrer,
+        referrer ? Services.io.newURI(referrer) : null);
+
       mainWin.setContextMenuContentData(data);
     }
   }
 
   /**
    * Some things are not serializable, so we either have to only send
    * their needed data or regenerate them in nsContextMenu.js
    * - target and target.ownerDocument
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -309,18 +309,17 @@ function openLinkIn(url, where, params) 
   let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
                                             "nsIReferrerInfo",
                                             "init");
 
   var aFromChrome           = params.fromChrome;
   var aAllowThirdPartyFixup = params.allowThirdPartyFixup;
   var aPostData             = params.postData;
   var aCharset              = params.charset;
-  var aReferrerInfo       = ("referrerInfo" in params)
-    ? params.referrerInfo
+  var aReferrerInfo       = params.referrerInfo ? params.referrerInfo
     : new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, null);
   var aRelatedToCurrent     = params.relatedToCurrent;
   var aAllowInheritPrincipal = !!params.allowInheritPrincipal;
   var aAllowMixedContent    = params.allowMixedContent;
   var aForceAllowDataURI    = params.forceAllowDataURI;
   var aInBackground         = params.inBackground;
   var aInitiatingDoc        = params.initiatingDoc;
   var aIsPrivate            = params.private;
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -45,16 +45,30 @@ var MigrationWizard = { /* exported Migr
 
       if (this._autoMigrate) {
         // Show the "nothing" option in the automigrate case to provide an
         // easily identifiable way to avoid migration and create a new profile.
         document.getElementById("nothing").hidden = false;
       }
     }
 
+    document.addEventListener("wizardcancel", function() { MigrationWizard.onWizardCancel(); });
+
+    document.getElementById("selectProfile").addEventListener("pageshow", function() { MigrationWizard.onSelectProfilePageShow(); });
+    document.getElementById("importItems").addEventListener("pageshow", function() { MigrationWizard.onImportItemsPageShow(); });
+    document.getElementById("migrating").addEventListener("pageshow", function() { MigrationWizard.onMigratingPageShow(); });
+    document.getElementById("done").addEventListener("pageshow", function() { MigrationWizard.onDonePageShow(); });
+
+    document.getElementById("selectProfile").addEventListener("pagerewound", function() { MigrationWizard.onSelectProfilePageRewound(); });
+    document.getElementById("importItems").addEventListener("pagerewound", function() { MigrationWizard.onImportItemsPageRewound(); });
+
+    document.getElementById("selectProfile").addEventListener("pageadvanced", function() { MigrationWizard.onSelectProfilePageAdvanced(); });
+    document.getElementById("importItems").addEventListener("pageadvanced", function() { MigrationWizard.onImportItemsPageAdvanced(); });
+    document.getElementById("importSource").addEventListener("pageadvanced", function(e) { MigrationWizard.onImportSourcePageAdvanced(e); });
+
     this.onImportSourcePageShow();
   },
 
   uninit() {
     var os = Services.obs;
     os.removeObserver(this, "Migration:Started");
     os.removeObserver(this, "Migration:ItemBeforeMigrate");
     os.removeObserver(this, "Migration:ItemAfterMigrate");
@@ -140,27 +154,27 @@ var MigrationWizard = { /* exported Migr
 
     // Advance to the next page if the caller told us to.
     if (this._migrator && this._skipImportSourcePage) {
       this._wiz.advance();
       this._wiz.canRewind = false;
     }
   },
 
-  onImportSourcePageAdvanced() {
+  onImportSourcePageAdvanced(event) {
     var newSource = document.getElementById("importSourceGroup").selectedItem.id;
 
     if (newSource == "nothing") {
       // Need to do telemetry here because we're closing the dialog before we get to
       // do actual migration. For actual migration, this doesn't happen until after
       // migration takes place.
       Services.telemetry.getHistogramById("FX_MIGRATION_SOURCE_BROWSER")
                         .add(MigrationUtils.getSourceIdForTelemetry("nothing"));
       document.documentElement.cancel();
-      return false;
+      event.preventDefault();
     }
 
     if (!this._migrator || (newSource != this._source)) {
       // Create the migrator for the selected source.
       this._migrator = this.spinResolve(MigrationUtils.getMigrator(newSource));
 
       this._itemsFlags = kIMig.ALL;
       this._selectedProfile = null;
@@ -179,17 +193,16 @@ var MigrationWizard = { /* exported Migr
       else
         this._wiz.currentPage.next = "importItems";
 
       if (sourceProfiles && sourceProfiles.length == 1)
         this._selectedProfile = sourceProfiles[0];
       else
         this._selectedProfile = null;
     }
-    return undefined;
   },
 
   // 2 - [Profile Selection]
   onSelectProfilePageShow() {
     // Disabling this for now, since we ask about import sources in automigration
     // too and don't want to disable the back button
     // if (this._autoMigrate)
     //   document.documentElement.getButton("back").disabled = true;
--- a/browser/components/migration/content/migration.xul
+++ b/browser/components/migration/content/migration.xul
@@ -10,25 +10,23 @@
 <wizard id="migrationWizard"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         windowtype="Browser:MigrationWizard"
         title="&migrationWizard.title;"
         onload="MigrationWizard.init()"
         onunload="MigrationWizard.uninit()"
         style="width: 40em;"
         buttons="accept,cancel"
-        branded="true"
-        onwizardcancel="return MigrationWizard.onWizardCancel();">
+        branded="true">
 
   <script type="application/javascript" src="chrome://global/content/customElements.js"/>
   <script type="application/javascript" src="chrome://browser/content/migration/migration.js"/>
 
   <wizardpage id="importSource" pageid="importSource" next="selectProfile"
-              label="&importSource.title;"
-              onpageadvanced="return MigrationWizard.onImportSourcePageAdvanced();">
+              label="&importSource.title;">
 #ifdef XP_WIN
     <description id="importAll" control="importSourceGroup">&importFrom.label;</description>
 #else
     <description id="importAll" control="importSourceGroup">&importFromUnix.label;</description>
 #endif
     <description id="importBookmarks" control="importSourceGroup" hidden="true">&importFromBookmarks.label;</description>
 
     <radiogroup id="importSourceGroup" align="start">
@@ -55,45 +53,36 @@
       <radio id="nothing"   label="&importFromNothing.label;"   accesskey="&importFromNothing.accesskey;" hidden="true"/>
     </radiogroup>
     <label id="noSources" hidden="true">&noMigrationSources.label;</label>
     <spacer flex="1"/>
     <description class="header" id="closeSourceBrowser" style="visibility:hidden">&closeSourceBrowser.label;</description>
   </wizardpage>
 
   <wizardpage id="selectProfile" pageid="selectProfile" label="&selectProfile.title;"
-              next="importItems"
-              onpageshow="return MigrationWizard.onSelectProfilePageShow();"
-              onpagerewound="return MigrationWizard.onSelectProfilePageRewound();"
-              onpageadvanced="return MigrationWizard.onSelectProfilePageAdvanced();">
+              next="importItems">
     <description control="profiles">&selectProfile.label;</description>
 
     <radiogroup id="profiles" align="left"/>
   </wizardpage>
 
   <wizardpage id="importItems" pageid="importItems" label="&importItems.title;"
               next="migrating"
-              onpageshow="return MigrationWizard.onImportItemsPageShow();"
-              onpagerewound="return MigrationWizard.onImportItemsPageRewound();"
-              onpageadvanced="return MigrationWizard.onImportItemsPageAdvanced();"
               oncommand="MigrationWizard.onImportItemCommand();">
     <description control="dataSources">&importItems.label;</description>
 
     <vbox id="dataSources" style="overflow: auto; -moz-appearance: listbox" align="left" flex="1" role="group"/>
   </wizardpage>
 
   <wizardpage id="migrating" pageid="migrating" label="&migrating.title;"
-              next="done"
-              onpageshow="MigrationWizard.onMigratingPageShow();">
+              next="done">
     <description control="migratingItems">&migrating.label;</description>
 
     <vbox id="migratingItems" style="overflow: auto;" align="left" role="group"/>
   </wizardpage>
 
-  <wizardpage id="done" pageid="done" label="&done.title;"
-              onpageshow="MigrationWizard.onDonePageShow();">
+  <wizardpage id="done" pageid="done" label="&done.title;">
     <description control="doneItems">&done.label;</description>
 
     <vbox id="doneItems" style="overflow: auto;" align="left" role="group"/>
   </wizardpage>
 
 </wizard>
-
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -1313,17 +1313,20 @@ var UITour = {
       // for URLBar's dropdown. To limit the search results on browser-related
       // items, we use "Firefox" hard-coded rather than l10n brandShortName
       // entity to avoid unrelated or unpredicted results for, like, Nightly
       // or translated entites.
       const SEARCH_STRING = "Firefox";
       urlbar.value = SEARCH_STRING;
       urlbar.select();
       if (quantumbar) {
-        urlbar.startQuery();
+        urlbar.startQuery({
+          searchString: SEARCH_STRING,
+          allowAutofill: false,
+        });
       } else {
         urlbar.controller.startSearch(SEARCH_STRING);
       }
     }
   },
 
   hideMenu(aWindow, aMenuName) {
     log.debug("hideMenu:", aMenuName);
--- a/browser/components/urlbar/tests/UrlbarTestUtils.jsm
+++ b/browser/components/urlbar/tests/UrlbarTestUtils.jsm
@@ -458,24 +458,22 @@ class UrlbarAbstraction {
       let typeIcon = element.querySelector(".urlbarView-type-icon");
       let typeIconStyle = this.window.getComputedStyle(typeIcon);
       details.displayed = {
         title: element.getElementsByClassName("urlbarView-title")[0].textContent,
         action: actions.length > 0 ? actions[0].textContent : null,
         url: urls.length > 0 ? urls[0].textContent : null,
         typeIcon: typeIconStyle["background-image"],
       };
-      let actionElement = element.getElementsByClassName("urlbarView-action")[0];
-      let urlElement = element.getElementsByClassName("urlbarView-url")[0];
       details.element = {
-        action: actionElement,
+        action: element.getElementsByClassName("urlbarView-action")[0],
         row: element,
-        separator: urlElement || actionElement,
+        separator: element.getElementsByClassName("urlbarView-title-separator")[0],
         title: element.getElementsByClassName("urlbarView-title")[0],
-        url: urlElement,
+        url: element.getElementsByClassName("urlbarView-url")[0],
       };
       if (details.type == UrlbarUtils.RESULT_TYPE.SEARCH) {
         details.searchParams = {
           engine: context.results[index].payload.engine,
           keyword: context.results[index].payload.keyword,
           query: context.results[index].payload.query,
           suggestion: context.results[index].payload.suggestion,
         };
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1314,17 +1314,16 @@ menuitem.panel-subview-footer@menuStateA
   margin-inline-start: 6px;
   margin-inline-end: 7px;
 }
 
 .subviewbutton > .menu-accel-container {
   -moz-box-pack: end;
   margin-inline-start: 10px;
   margin-inline-end: auto;
-  color: var(--panel-disabled-color);
 }
 
 #PanelUI-remotetabs-tabslist > toolbarbutton[itemtype="tab"],
 #PanelUI-historyItems > toolbarbutton {
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
   -moz-context-properties: fill;
   fill: currentColor;
 }
--- a/build/build-clang/clang-8-android.json
+++ b/build/build-clang/clang-8-android.json
@@ -42,11 +42,11 @@
           "/builds/worker/workspace/build/src/android-ndk/sysroot/usr/include"
         ],
         "api_level": 21
       }
     },
     "patches": [
       "static-llvm-symbolizer.patch",
       "find_symbolizer_linux.patch",
-      "rename_gcov_flush_.patch"
+      "rename_gcov_flush.patch"
     ]
 }
--- a/build/build-clang/clang-8-linux64.json
+++ b/build/build-clang/clang-8-linux64.json
@@ -13,12 +13,12 @@
     "python_path": "/usr/bin/python2.7",
     "gcc_dir": "/builds/worker/workspace/build/src/gcc",
     "cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
     "cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
     "as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
     "patches": [
       "static-llvm-symbolizer.patch",
       "find_symbolizer_linux.patch",
-      "rename_gcov_flush_.patch",
+      "rename_gcov_flush.patch",
       "android-mangling-error.patch"
     ]
 }
--- a/build/build-clang/clang-8-macosx64.json
+++ b/build/build-clang/clang-8-macosx64.json
@@ -17,12 +17,13 @@
     "cxx": "/builds/worker/workspace/build/src/clang/bin/clang++",
     "as": "/builds/worker/workspace/build/src/clang/bin/clang",
     "ar": "/builds/worker/workspace/build/src/cctools/bin/x86_64-darwin11-ar",
     "ranlib": "/builds/worker/workspace/build/src/cctools/bin/x86_64-darwin11-ranlib",
     "libtool": "/builds/worker/workspace/build/src/cctools/bin/x86_64-darwin11-libtool",
     "ld": "/builds/worker/workspace/build/src/clang/bin/clang",
     "patches": [
       "static-llvm-symbolizer.patch",
+      "rename_gcov_flush.patch",
       "compiler-rt-cross-compile.patch",
       "compiler-rt-no-codesign.patch"
     ]
 }
new file mode 100644
--- /dev/null
+++ b/build/build-clang/rename_gcov_flush.patch
@@ -0,0 +1,40 @@
+Index: compiler-rt/lib/profile/GCDAProfiling.c
+===================================================================
+diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
+--- a/compiler-rt/lib/profile/GCDAProfiling.c	(revisione 336380)
++++ b/compiler-rt/lib/profile/GCDAProfiling.c	(copia locale)
+@@ -555,7 +555,7 @@
+   fn_list_insert(&flush_fn_list, fn);
+ }
+ 
+-void __gcov_flush() {
++void __custom_llvm_gcov_flush() {
+   struct fn_node* curr = flush_fn_list.head;
+ 
+   while (curr) {
+diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+index 9af64ed332c..bcebe303ff4 100644
+--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
++++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+@@ -648,7 +648,7 @@ void GCOVProfiler::AddFlushBeforeForkAndExec() {
+   for (auto I : ForkAndExecs) {
+     IRBuilder<> Builder(I);
+     FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false);
+-    Constant *GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy);
++    Constant *GCOVFlush = M->getOrInsertFunction("__custom_llvm_gcov_flush", FTy);
+     Builder.CreateCall(GCOVFlush);
+     I->getParent()->splitBasicBlock(I);
+   }
+diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
+index e113f9a679..b3a07b18c0 100644
+--- a/clang/lib/Driver/ToolChains/Darwin.cpp
++++ b/clang/lib/Driver/ToolChains/Darwin.cpp
+@@ -1058,7 +1058,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
+   // runtime's functionality.
+   if (hasExportSymbolDirective(Args)) {
+     if (needsGCovInstrumentation(Args)) {
+-      addExportedSymbol(CmdArgs, "___gcov_flush");
++      addExportedSymbol(CmdArgs, "___custom_llvm_gcov_flush");
+       addExportedSymbol(CmdArgs, "_flush_fn_list");
+       addExportedSymbol(CmdArgs, "_writeout_fn_list");
+     } else {
deleted file mode 100644
--- a/build/build-clang/rename_gcov_flush_.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-Index: compiler-rt/lib/profile/GCDAProfiling.c
-===================================================================
-diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
---- a/compiler-rt/lib/profile/GCDAProfiling.c	(revisione 336380)
-+++ b/compiler-rt/lib/profile/GCDAProfiling.c	(copia locale)
-@@ -555,7 +555,7 @@
-   fn_list_insert(&flush_fn_list, fn);
- }
- 
--void __gcov_flush() {
-+void __custom_llvm_gcov_flush() {
-   struct fn_node* curr = flush_fn_list.head;
- 
-   while (curr) {
-diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
-index 9af64ed332c..bcebe303ff4 100644
---- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
-+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
-@@ -648,7 +648,7 @@ void GCOVProfiler::AddFlushBeforeForkAndExec() {
-   for (auto I : ForkAndExecs) {
-     IRBuilder<> Builder(I);
-     FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false);
--    Constant *GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy);
-+    Constant *GCOVFlush = M->getOrInsertFunction("__custom_llvm_gcov_flush", FTy);
-     Builder.CreateCall(GCOVFlush);
-     I->getParent()->splitBasicBlock(I);
-   }
--- a/devtools/client/aboutdebugging-new/src/actions/runtimes.js
+++ b/devtools/client/aboutdebugging-new/src/actions/runtimes.js
@@ -19,16 +19,17 @@ const {
   isSupportedDebugTargetPane,
 } = require("../modules/debug-target-support");
 
 const { remoteClientManager } =
   require("devtools/client/shared/remote-debugging/remote-client-manager");
 
 const {
   CONNECT_RUNTIME_FAILURE,
+  CONNECT_RUNTIME_NOT_RESPONDING,
   CONNECT_RUNTIME_START,
   CONNECT_RUNTIME_SUCCESS,
   DEBUG_TARGET_PANE,
   DISCONNECT_RUNTIME_FAILURE,
   DISCONNECT_RUNTIME_START,
   DISCONNECT_RUNTIME_SUCCESS,
   PAGE_TYPES,
   REMOTE_RUNTIMES_UPDATED,
@@ -47,16 +48,18 @@ const {
   UPDATE_RUNTIME_MULTIE10S_FAILURE,
   UPDATE_RUNTIME_MULTIE10S_START,
   UPDATE_RUNTIME_MULTIE10S_SUCCESS,
   WATCH_RUNTIME_FAILURE,
   WATCH_RUNTIME_START,
   WATCH_RUNTIME_SUCCESS,
 } = require("../constants");
 
+const CONNECTION_TIMING_OUT_DELAY = 3000;
+
 async function getRuntimeIcon(channel) {
   return (channel === "release" || channel === "beta" || channel === "aurora")
     ? `chrome://devtools/skin/images/aboutdebugging-firefox-${ channel }.svg`
     : "chrome://devtools/skin/images/aboutdebugging-firefox-nightly.svg";
 }
 
 function onRemoteDebuggerClientClosed() {
   window.AboutDebugging.onNetworkLocationsUpdated();
@@ -64,17 +67,24 @@ function onRemoteDebuggerClientClosed() 
 }
 
 function onMultiE10sUpdated() {
   window.AboutDebugging.store.dispatch(updateMultiE10s());
 }
 
 function connectRuntime(id) {
   return async (dispatch, getState) => {
-    dispatch({ type: CONNECT_RUNTIME_START });
+    dispatch({ type: CONNECT_RUNTIME_START, id });
+    const connectionNotRespondingTimer = setTimeout(() => {
+      // If connecting to the runtime takes time over CONNECTION_TIMING_OUT_DELAY,
+      // we assume the connection prompt is showing on the runtime, show a dialog
+      // to let user know that.
+      dispatch({ type: CONNECT_RUNTIME_NOT_RESPONDING, id });
+    }, CONNECTION_TIMING_OUT_DELAY);
+
     try {
       const runtime = findRuntimeById(id, getState().runtimes);
       const clientWrapper = await createClientForRuntime(runtime);
 
       const deviceDescription = await clientWrapper.getDeviceDescription();
       const compatibilityReport = await clientWrapper.checkVersionCompatibility();
       const icon = await getRuntimeIcon(deviceDescription.channel);
 
@@ -130,25 +140,30 @@ function connectRuntime(id) {
         type: CONNECT_RUNTIME_SUCCESS,
         runtime: {
           id,
           runtimeDetails,
           type: runtime.type,
         },
       });
     } catch (e) {
-      dispatch({ type: CONNECT_RUNTIME_FAILURE, error: e });
+      dispatch({ type: CONNECT_RUNTIME_FAILURE, id, error: e });
+    } finally {
+      clearTimeout(connectionNotRespondingTimer);
     }
   };
 }
 
 function createThisFirefoxRuntime() {
   return (dispatch, getState) => {
     const thisFirefoxRuntime = {
       id: RUNTIMES.THIS_FIREFOX,
+      isConnecting: false,
+      isConnectionFailed: false,
+      isConnectionNotResponding: false,
       isUnknown: false,
       name: l10n.getString("about-debugging-this-firefox-runtime-name"),
       type: RUNTIMES.THIS_FIREFOX,
     };
     dispatch({ type: THIS_FIREFOX_RUNTIME_CREATED, runtime: thisFirefoxRuntime });
   };
 }
 
@@ -297,16 +312,19 @@ function unwatchRuntime(id) {
 function updateNetworkRuntimes(locations) {
   const runtimes = locations.map(location => {
     const [ host, port ] = location.split(":");
     return {
       id: location,
       extra: {
         connectionParameters: { host, port: parseInt(port, 10) },
       },
+      isConnecting: false,
+      isConnectionFailed: false,
+      isConnectionNotResponding: false,
       isUnknown: false,
       name: location,
       type: RUNTIMES.NETWORK,
     };
   });
   return updateRemoteRuntimes(runtimes, RUNTIMES.NETWORK);
 }
 
@@ -317,16 +335,19 @@ function updateUSBRuntimes(adbRuntimes) 
     const deviceId = adbRuntime.deviceId;
     const connectionParameters = adbRuntime.isUnknown() ? null : { deviceId, socketPath };
     return {
       id: adbRuntime.id,
       extra: {
         connectionParameters,
         deviceName: adbRuntime.deviceName,
       },
+      isConnecting: false,
+      isConnectionFailed: false,
+      isConnectionNotResponding: false,
       isUnknown: adbRuntime.isUnknown(),
       name: adbRuntime.shortName,
       type: RUNTIMES.USB,
     };
   });
   return updateRemoteRuntimes(runtimes, RUNTIMES.USB);
 }
 
@@ -358,22 +379,33 @@ function updateRemoteRuntimes(runtimes, 
       //
       // The reason we call selectPage before REMOTE_RUNTIMES_UPDATED is fired is below.
       // Current runtime can not be retrieved after REMOTE_RUNTIMES_UPDATED action, since
       // that updates runtime state. So, before that we fire selectPage action to execute
       // `unwatchRuntime` correctly.
       await dispatch(Actions.selectPage(PAGE_TYPES.RUNTIME, RUNTIMES.THIS_FIREFOX));
     }
 
-    // Retrieve runtimeDetails from existing runtimes.
+    // For existing runtimes, transfer all properties that are not available in the
+    // runtime objects passed to this method:
+    // - runtimeDetails (set by about:debugging after a successful connection)
+    // - isConnecting (set by about:debugging during the connection)
+    // - isConnectionFailed (set by about:debugging if connection was failed)
+    // - isConnectionNotResponding
+    //     (set by about:debugging if connection is taking too much time)
     runtimes.forEach(runtime => {
       const existingRuntime = findRuntimeById(runtime.id, getState().runtimes);
       const isConnectionValid = existingRuntime && existingRuntime.runtimeDetails &&
         !existingRuntime.runtimeDetails.clientWrapper.isClosed();
       runtime.runtimeDetails = isConnectionValid ? existingRuntime.runtimeDetails : null;
+      runtime.isConnecting = existingRuntime ? existingRuntime.isConnecting : false;
+      runtime.isConnectionFailed =
+        existingRuntime ? existingRuntime.isConnectionFailed : false;
+      runtime.isConnectionNotResponding =
+        existingRuntime ? existingRuntime.isConnectionNotResponding : false;
     });
 
     const existingRuntimes = getAllRuntimes(getState().runtimes);
     for (const runtime of existingRuntimes) {
       // Runtime was connected before.
       const isConnected = runtime.runtimeDetails;
       // Runtime is of the same type as the updated runtimes array, so we should check it.
       const isSameType = runtime.type === type;
--- a/devtools/client/aboutdebugging-new/src/base.css
+++ b/devtools/client/aboutdebugging-new/src/base.css
@@ -158,16 +158,21 @@ p, h1 {
 
 /* Links that need to look like current text */
 .undecorated-link,
 .undecorated-link:hover {
   text-decoration: none;
   color: currentColor;
 }
 
+/* Text needs to wrap anywhere */
+.word-wrap-anywhere {
+  word-wrap: anywhere;
+}
+
 /*
 * Typography
 */
 
 /* Main style for heading (i.e. h1) */
 .main-heading {
   font-size: var(--display-20-font-size);
   font-weight: var(--display-20-font-weight);
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
+++ b/devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.js
@@ -108,16 +108,19 @@ class Sidebar extends PureComponent {
       }
 
       return SidebarRuntimeItem({
         deviceName: runtime.extra.deviceName,
         dispatch,
         icon,
         key: keyId,
         isConnected: runtimeHasDetails,
+        isConnecting: runtime.isConnecting,
+        isConnectionFailed: runtime.isConnectionFailed,
+        isConnectionNotResponding: runtime.isConnectionNotResponding,
         isSelected,
         isUnknown: runtime.isUnknown,
         name,
         runtimeId: runtime.id,
       });
     });
   }
 
--- a/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js
+++ b/devtools/client/aboutdebugging-new/src/components/sidebar/SidebarRuntimeItem.js
@@ -6,52 +6,112 @@
 
 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 FluentReact = require("devtools/client/shared/vendor/fluent-react");
 const Localized = createFactory(FluentReact.Localized);
 
+const Message = createFactory(require("../shared/Message"));
 const SidebarItem = createFactory(require("./SidebarItem"));
 const Actions = require("../../actions/index");
+const { MESSAGE_LEVEL } = require("../../constants");
 
 /**
  * This component displays a runtime item of the Sidebar component.
  */
 class SidebarRuntimeItem extends PureComponent {
   static get propTypes() {
     return {
       deviceName: PropTypes.string,
       dispatch: PropTypes.func.isRequired,
       // Provided by wrapping the component with FluentReact.withLocalization.
       getString: PropTypes.func.isRequired,
       icon: PropTypes.string.isRequired,
       isConnected: PropTypes.bool.isRequired,
+      isConnecting: PropTypes.bool.isRequired,
+      isConnectionFailed: PropTypes.bool.isRequired,
+      isConnectionNotResponding: PropTypes.bool.isRequired,
       isSelected: PropTypes.bool.isRequired,
       isUnknown: PropTypes.bool.isRequired,
       name: PropTypes.string.isRequired,
       runtimeId: PropTypes.string.isRequired,
     };
   }
 
   renderConnectButton() {
+    const { isConnecting } = this.props;
+    const localizationId = isConnecting
+                             ? "about-debugging-sidebar-item-connect-button-connecting"
+                             : "about-debugging-sidebar-item-connect-button";
     return Localized(
       {
-        id: "about-debugging-sidebar-item-connect-button",
+        id: localizationId,
       },
       dom.button(
         {
           className: "default-button default-button--micro js-connect-button",
+          disabled: isConnecting,
           onClick: () => {
             const { dispatch, runtimeId } = this.props;
             dispatch(Actions.connectRuntime(runtimeId));
           },
         },
-        "Connect"
+        localizationId
+      )
+    );
+  }
+
+  renderConnectionError() {
+    const { isConnectionFailed } = this.props;
+
+    if (!isConnectionFailed) {
+      return null;
+    }
+
+    const localizationId =
+      "about-debugging-sidebar-item-connect-button-connection-failed";
+
+    return Message(
+      {
+        level: MESSAGE_LEVEL.ERROR,
+        key: "connection-error",
+        className: "qa-connection-error",
+      },
+      Localized(
+        {
+          id: localizationId,
+        },
+        dom.p({ className: "word-wrap-anywhere" }, localizationId)
+      )
+    );
+  }
+
+  renderConnectionNotResponding() {
+    const { isConnectionNotResponding } = this.props;
+
+    if (!isConnectionNotResponding) {
+      return null;
+    }
+
+    const localizationId =
+      "about-debugging-sidebar-item-connect-button-connection-not-responding";
+
+    return Message(
+      {
+        level: MESSAGE_LEVEL.WARNING,
+        key: "connection-not-responding",
+        className: "qa-connection-not-responding",
+      },
+      Localized(
+        {
+          id: localizationId,
+        },
+        dom.p({ className: "word-wrap-anywhere" }, localizationId)
       )
     );
   }
 
   renderName() {
     const { deviceName, getString, isUnknown, name } = this.props;
 
     const displayName = isUnknown ?
@@ -110,34 +170,39 @@ class SidebarRuntimeItem extends PureCom
       isUnknown,
       runtimeId,
     } = this.props;
 
     const connectionStatus = isConnected ?
       getString("aboutdebugging-sidebar-runtime-connection-status-connected") :
       getString("aboutdebugging-sidebar-runtime-connection-status-disconnected");
 
-    return SidebarItem(
-      {
-        className: "sidebar-item--tall",
-        isSelected,
-        to: isConnected ? `/runtime/${encodeURIComponent(runtimeId)}` : null,
-      },
-      dom.section(
+    return [
+      SidebarItem(
         {
-          className: "sidebar-runtime-item__container",
+          className: "sidebar-item--tall",
+          key: "sidebar-item",
+          isSelected,
+          to: isConnected ? `/runtime/${encodeURIComponent(runtimeId)}` : null,
         },
-        dom.img(
+        dom.section(
           {
-            className: "sidebar-runtime-item__icon ",
-            src: icon,
-            alt: connectionStatus,
-            title: connectionStatus,
-          }
+            className: "sidebar-runtime-item__container",
+          },
+          dom.img(
+            {
+              className: "sidebar-runtime-item__icon ",
+              src: icon,
+              alt: connectionStatus,
+              title: connectionStatus,
+            }
+          ),
+          this.renderName(),
+          !isUnknown && !isConnected ? this.renderConnectButton() : null
         ),
-        this.renderName(),
-        !isUnknown && !isConnected ? this.renderConnectButton() : null
-      )
-    );
+      ),
+      this.renderConnectionError(),
+      this.renderConnectionNotResponding(),
+    ];
   }
 }
 
 module.exports = FluentReact.withLocalization(SidebarRuntimeItem);
--- a/devtools/client/aboutdebugging-new/src/constants.js
+++ b/devtools/client/aboutdebugging-new/src/constants.js
@@ -11,16 +11,17 @@ const actionTypes = {
   ADB_ADDON_INSTALL_START: "ADB_ADDON_INSTALL_START",
   ADB_ADDON_INSTALL_SUCCESS: "ADB_ADDON_INSTALL_SUCCESS",
   ADB_ADDON_INSTALL_FAILURE: "ADB_ADDON_INSTALL_FAILURE",
   ADB_ADDON_UNINSTALL_START: "ADB_ADDON_UNINSTALL_START",
   ADB_ADDON_UNINSTALL_SUCCESS: "ADB_ADDON_UNINSTALL_SUCCESS",
   ADB_ADDON_UNINSTALL_FAILURE: "ADB_ADDON_UNINSTALL_FAILURE",
   ADB_ADDON_STATUS_UPDATED: "ADB_ADDON_STATUS_UPDATED",
   CONNECT_RUNTIME_FAILURE: "CONNECT_RUNTIME_FAILURE",
+  CONNECT_RUNTIME_NOT_RESPONDING: "CONNECT_RUNTIME_NOT_RESPONDING",
   CONNECT_RUNTIME_START: "CONNECT_RUNTIME_START",
   CONNECT_RUNTIME_SUCCESS: "CONNECT_RUNTIME_SUCCESS",
   DEBUG_TARGET_COLLAPSIBILITY_UPDATED: "DEBUG_TARGET_COLLAPSIBILITY_UPDATED",
   DISCONNECT_RUNTIME_FAILURE: "DISCONNECT_RUNTIME_FAILURE",
   DISCONNECT_RUNTIME_START: "DISCONNECT_RUNTIME_START",
   DISCONNECT_RUNTIME_SUCCESS: "DISCONNECT_RUNTIME_SUCCESS",
   HIDE_PROFILER_DIALOG: "HIDE_PROFILER_DIALOG",
   NETWORK_LOCATIONS_UPDATED: "NETWORK_LOCATIONS_UPDATED",
--- a/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js
+++ b/devtools/client/aboutdebugging-new/src/reducers/runtimes-state.js
@@ -1,15 +1,18 @@
 /* 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/. */
 
 "use strict";
 
 const {
+  CONNECT_RUNTIME_FAILURE,
+  CONNECT_RUNTIME_NOT_RESPONDING,
+  CONNECT_RUNTIME_START,
   CONNECT_RUNTIME_SUCCESS,
   DISCONNECT_RUNTIME_SUCCESS,
   RUNTIMES,
   UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS,
   UPDATE_EXTENSION_DEBUG_SETTING_SUCCESS,
   UPDATE_RUNTIME_MULTIE10S_SUCCESS,
   REMOTE_RUNTIMES_UPDATED,
   SELECTED_RUNTIME_ID_UPDATED,
@@ -67,20 +70,51 @@ function _updateRuntimeById(runtimeId, u
     }
     return r;
   });
   return Object.assign({}, state, { [key]: updatedRuntimes });
 }
 
 function runtimesReducer(state = RuntimesState(), action) {
   switch (action.type) {
+    case CONNECT_RUNTIME_START: {
+      const { id } = action;
+      const updatedState = {
+        isConnecting: true,
+        isConnectionFailed: false,
+        isConnectionNotResponding: false,
+      };
+      return _updateRuntimeById(id, updatedState, state);
+    }
+
+    case CONNECT_RUNTIME_NOT_RESPONDING: {
+      const { id } = action;
+      return _updateRuntimeById(id, { isConnectionNotResponding: true }, state);
+    }
+
     case CONNECT_RUNTIME_SUCCESS: {
       const { id, runtimeDetails, type } = action.runtime;
       remoteClientManager.setClient(id, type, runtimeDetails.clientWrapper.client);
-      return _updateRuntimeById(id, { runtimeDetails }, state);
+      const updatedState = {
+        isConnecting: false,
+        isConnectionFailed: false,
+        isConnectionNotResponding: false,
+        runtimeDetails,
+      };
+      return _updateRuntimeById(id, updatedState, state);
+    }
+
+    case CONNECT_RUNTIME_FAILURE: {
+      const { id } = action;
+      const updatedState = {
+        isConnecting: false,
+        isConnectionFailed: true,
+        isConnectionNotResponding: false,
+      };
+      return _updateRuntimeById(id, updatedState, state);
     }
 
     case DISCONNECT_RUNTIME_SUCCESS: {
       const { id, type } = action.runtime;
       remoteClientManager.removeClient(id, type);
       return _updateRuntimeById(id, { runtimeDetails: null }, state);
     }
 
--- a/devtools/client/aboutdebugging-new/src/types/runtime.js
+++ b/devtools/client/aboutdebugging-new/src/types/runtime.js
@@ -110,16 +110,27 @@ const runtimeExtra = {
 const runtime = {
   // unique id for the runtime
   id: PropTypes.string.isRequired,
 
   // object containing non standard properties that depend on the runtime type,
   // unavailable on this-firefox runtime
   extra: PropTypes.shape(runtimeExtra),
 
+  // this flag will be true when start to connect to the runtime, will be false after
+  // connected or has failures.
+  isConnecting: PropTypes.bool.isRequired,
+
+  // this flag will be true when the connection failed.
+  isConnectionFailed: PropTypes.bool.isRequired,
+
+  // will be true if connecting to runtime is taking time, will be false after connecting
+  // or failing.
+  isConnectionNotResponding: PropTypes.bool.isRequired,
+
   // unknown runtimes are placeholders for devices where the runtime has not been started
   // yet. For instance an ADB device connected without a compatible runtime running.
   isUnknown: PropTypes.bool.isRequired,
 
   // display name of the runtime
   name: PropTypes.string.isRequired,
 
   // available after the connection to the runtime is established
--- a/devtools/client/aboutdebugging-new/test/browser/browser.ini
+++ b/devtools/client/aboutdebugging-new/test/browser/browser.ini
@@ -81,16 +81,17 @@ skip-if = debug || asan || serviceworker
 [browser_aboutdebugging_serviceworker_push.js]
 [browser_aboutdebugging_serviceworker_pushservice_url.js]
 [browser_aboutdebugging_serviceworker_runtime-page.js]
 [browser_aboutdebugging_serviceworker_start.js]
 [browser_aboutdebugging_serviceworker_status.js]
 [browser_aboutdebugging_serviceworker_timeout.js]
 skip-if = debug || asan # Frequent intermittent failures, Bug 1522800
 [browser_aboutdebugging_serviceworker_unregister.js]
+[browser_aboutdebugging_sidebar_connection_state.js]
 [browser_aboutdebugging_sidebar_network_runtimes.js]
 [browser_aboutdebugging_sidebar_usb_runtime.js]
 [browser_aboutdebugging_sidebar_usb_runtime_connect.js]
 [browser_aboutdebugging_sidebar_usb_runtime_refresh.js]
 [browser_aboutdebugging_sidebar_usb_runtime_select.js]
 [browser_aboutdebugging_sidebar_usb_status.js]
 skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug 1499638
 [browser_aboutdebugging_sidebar_usb_unknown_runtime.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_connection_state.js
@@ -0,0 +1,78 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const RUNTIME_ID = "test-runtime-id";
+const RUNTIME_NAME = "test runtime name";
+const RUNTIME_DEVICE_NAME = "test device name";
+const RUNTIME_SHORT_NAME = "test short name";
+
+// Test following connection state tests.
+// * Connect button label and state will change during connecting.
+// * Show error message if connection failed.
+// * Show warninng if connection has been taken time.
+add_task(async function() {
+  const mocks = new Mocks();
+
+  const { document, tab } = await openAboutDebugging();
+
+  mocks.createUSBRuntime(RUNTIME_ID, {
+    name: RUNTIME_NAME,
+    deviceName: RUNTIME_DEVICE_NAME,
+    shortName: RUNTIME_SHORT_NAME,
+  });
+  mocks.emitUSBUpdate();
+
+  info("Wait until the USB sidebar item appears");
+  await waitUntil(() => findSidebarItemByText(RUNTIME_DEVICE_NAME, document));
+  const usbRuntimeSidebarItem = findSidebarItemByText(RUNTIME_DEVICE_NAME, document);
+  const connectButton = usbRuntimeSidebarItem.querySelector(".js-connect-button");
+
+  info("Simulate to happen connection error");
+  mocks.runtimeClientFactoryMock.createClientForRuntime = async (runtime) => {
+    throw new Error("Dummy connection error");
+  };
+
+  info("Check whether the error message displayed after clicking connect button");
+  connectButton.click();
+  await waitUntil(() => document.querySelector(".qa-connection-error"));
+  ok(true, "Error message displays when connection failed");
+
+  info("Simulate to wait for the connection prompt on remote runtime");
+  let resumeConnection;
+  const resumeConnectionPromise = new Promise(r => {
+    resumeConnection = r;
+  });
+  mocks.runtimeClientFactoryMock.createClientForRuntime = async (runtime) => {
+    await resumeConnectionPromise;
+    return mocks._clients[runtime.type][runtime.id];
+  };
+
+  info("Click on the connect button and wait until it disappears");
+  connectButton.click();
+  info("Check whether a warning of connection not responding displays after 3sec");
+  await waitUntil(() => document.querySelector(".qa-connection-not-responding"));
+  ok(document.querySelector(".qa-connection-not-responding"),
+     "A warning of connection not responding displays");
+  ok(connectButton.disabled, "State of the connect button displays");
+  ok(connectButton.textContent.startsWith("Connecting"),
+     "Label of the connect button changes");
+  ok(!document.querySelector(".qa-connection-error"), "Error message disappears");
+
+  info("Unblock the connection and check the message and connect button disappear");
+  resumeConnection();
+  await waitUntil(() => !usbRuntimeSidebarItem.querySelector(".js-connect-button"));
+  ok(!document.querySelector(".qa-connection-error"), "Error disappears");
+  ok(!document.querySelector(".qa-connection-not-responding"), "Warning disappears");
+
+  info("Remove a USB runtime");
+  mocks.removeUSBRuntime(RUNTIME_ID);
+  mocks.emitUSBUpdate();
+
+  info("Wait until the USB sidebar item disappears");
+  await waitUntil(() => !findSidebarItemByText(RUNTIME_DEVICE_NAME, document) &&
+                      !findSidebarItemByText(RUNTIME_SHORT_NAME, document));
+
+  await removeTab(tab);
+});
--- a/devtools/client/debugger/new/packages/devtools-reps/src/reps/element-node.js
+++ b/devtools/client/debugger/new/packages/devtools-reps/src/reps/element-node.js
@@ -88,32 +88,36 @@ function ElementNode(props) {
   return span(baseConfig, ...elements, inspectIcon);
 }
 
 function getElements(grip, mode) {
   const {
     attributes,
     nodeName,
     isAfterPseudoElement,
-    isBeforePseudoElement
+    isBeforePseudoElement,
+    isMarkerPseudoElement
   } = grip.preview;
   const nodeNameElement = span(
     {
       className: "tag-name"
     },
     nodeName
   );
 
-  if (isAfterPseudoElement || isBeforePseudoElement) {
-    return [
-      span(
-        { className: "attrName" },
-        `::${isAfterPseudoElement ? "after" : "before"}`
-      )
-    ];
+  let pseudoNodeName;
+  if (isAfterPseudoElement) {
+    pseudoNodeName = "after";
+  } else if (isBeforePseudoElement) {
+    pseudoNodeName = "before";
+  } else if (isMarkerPseudoElement) {
+    pseudoNodeName = "marker";
+  }
+  if (pseudoNodeName) {
+    return [span({ className: "attrName" }, `::${pseudoNodeName}`)];
   }
 
   if (mode === MODE.TINY) {
     const elements = [nodeNameElement];
     if (attributes.id) {
       elements.push(span({ className: "attrName" }, `#${attributes.id}`));
     }
     if (attributes.class) {
--- a/devtools/client/debugger/new/packages/devtools-reps/src/reps/stubs/element-node.js
+++ b/devtools/client/debugger/new/packages/devtools-reps/src/reps/stubs/element-node.js
@@ -243,16 +243,29 @@ stubs.set("NodeWithLongStringAttribute",
         length: 50000,
         actor: "server1.conn1.child1/longString29"
       }
     },
     attributesLength: 1
   }
 });
 
+stubs.set("MarkerPseudoElement", {
+  type: "object",
+  actor: "server1.conn1.child1/obj26",
+  preview: {
+    kind: "DOMNode",
+    nodeType: 1,
+    nodeName: "_moz_generated_content_marker",
+    attributes: {},
+    attributesLength: 0,
+    isMarkerPseudoElement: true
+  }
+});
+
 stubs.set("BeforePseudoElement", {
   type: "object",
   actor: "server1.conn1.child1/obj27",
   preview: {
     kind: "DOMNode",
     nodeType: 1,
     nodeName: "_moz_generated_content_before",
     attributes: {},
--- a/devtools/client/debugger/new/packages/devtools-reps/src/reps/tests/element-node.js
+++ b/devtools/client/debugger/new/packages/devtools-reps/src/reps/tests/element-node.js
@@ -460,16 +460,45 @@ describe("ElementNode - Element attribut
       renderedComponent
         .first()
         .find("span.attrValue")
         .prop("title")
     ).toBe("a".repeat(1000));
   });
 });
 
+describe("ElementNode - : Marker pseudo element", () => {
+  const stub = stubs.get("MarkerPseudoElement");
+
+  it("selects ElementNode Rep", () => {
+    expect(getRep(stub)).toBe(ElementNode.rep);
+  });
+
+  it("renders with expected text content", () => {
+    const renderedComponent = shallow(
+      ElementNode.rep({
+        object: stub
+      })
+    );
+
+    expect(renderedComponent.text()).toEqual("::marker");
+  });
+
+  it("renders with expected text content in tiny mode", () => {
+    const renderedComponent = shallow(
+      ElementNode.rep({
+        object: stub,
+        mode: MODE.TINY
+      })
+    );
+
+    expect(renderedComponent.text()).toEqual("::marker");
+  });
+});
+
 describe("ElementNode - : Before pseudo element", () => {
   const stub = stubs.get("BeforePseudoElement");
 
   it("selects ElementNode Rep", () => {
     expect(getRep(stub)).toBe(ElementNode.rep);
   });
 
   it("renders with expected text content", () => {
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css
@@ -96,17 +96,17 @@
 .expression-container__close-btn {
   position: absolute;
   /* hiding button outside of row until hovered or focused */
   top: -100px;
 }
 
 .expression-container:hover .expression-container__close-btn,
 .expression-container__close-btn:focus-within {
-  top: calc(50% - 8px);
+  top: 0;
 }
 
 [dir="ltr"] .expression-container__close-btn {
   right: 0;
 }
 
 [dir="rtl"] .expression-container__close-btn {
   left: 0;
--- a/devtools/client/inspector/breadcrumbs.js
+++ b/devtools/client/inspector/breadcrumbs.js
@@ -423,18 +423,22 @@ HTMLBreadcrumbs.prototype = {
 
   /**
    * Build a string that represents the node: tagName#id.class1.class2.
    * @param {NodeFront} node The node to pretty-print
    * @return {String}
    */
   prettyPrintNodeAsText: function(node) {
     let text = node.isShadowRoot ? SHADOW_ROOT_TAGNAME : node.displayName;
-    if (node.isPseudoElement) {
-      text = node.isBeforePseudoElement ? "::before" : "::after";
+    if (node.isMarkerPseudoElement) {
+      text = "::marker";
+    } else if (node.isBeforePseudoElement) {
+      text = "::before";
+    } else if (node.isAfterPseudoElement) {
+      text = "::after";
     }
 
     if (node.id) {
       text += "#" + node.id;
     }
 
     if (node.className) {
       const classList = node.className.split(/\s+/);
@@ -467,18 +471,22 @@ HTMLBreadcrumbs.prototype = {
 
     const classesLabel = this.doc.createElementNS(NS_XHTML, "span");
     classesLabel.className = "breadcrumbs-widget-item-classes plain";
 
     const pseudosLabel = this.doc.createElementNS(NS_XHTML, "span");
     pseudosLabel.className = "breadcrumbs-widget-item-pseudo-classes plain";
 
     let tagText = node.isShadowRoot ? SHADOW_ROOT_TAGNAME : node.displayName;
-    if (node.isPseudoElement) {
-      tagText = node.isBeforePseudoElement ? "::before" : "::after";
+    if (node.isMarkerPseudoElement) {
+      tagText = "::marker";
+    } else if (node.isBeforePseudoElement) {
+      tagText = "::before";
+    } else if (node.isAfterPseudoElement) {
+      tagText = "::after";
     }
     let idText = node.id ? ("#" + node.id) : "";
     let classesText = "";
 
     if (node.className) {
       const classList = node.className.split(/\s+/);
       for (let i = 0; i < classList.length; i++) {
         classesText += "." + classList[i];
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -2175,22 +2175,26 @@ MarkupView.prototype = {
         target.previousElementSibling.nodeName.toLowerCase() === "ul") {
       parent = target.parentNode.container.node;
       nextSibling = null;
     } else {
       parent = target.parentNode.container.node.parentNode();
       nextSibling = target.parentNode.container.node;
     }
 
-    if (nextSibling && nextSibling.isBeforePseudoElement) {
-      nextSibling = target.parentNode.parentNode.children[1].container.node;
-    }
-    if (nextSibling && nextSibling.isAfterPseudoElement) {
-      parent = target.parentNode.container.node.parentNode();
-      nextSibling = null;
+    if (nextSibling) {
+      while (
+        nextSibling.isMarkerPseudoElement || nextSibling.isBeforePseudoElement
+      ) {
+        nextSibling = this.getContainer(nextSibling).elt.nextSibling.container.node;
+      }
+      if (nextSibling.isAfterPseudoElement) {
+        parent = target.parentNode.container.node.parentNode();
+        nextSibling = null;
+      }
     }
 
     if (parent.nodeType !== nodeConstants.ELEMENT_NODE) {
       return null;
     }
 
     return {parent, nextSibling};
   },
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -110,16 +110,17 @@ subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) || (os == "win" && processor == "aarch64") # bug 1328915, disable linux32 debug devtools for timeouts, disabled on aarch64 due to 1531598
 [browser_markup_css_completion_style_attribute_01.js]
 [browser_markup_css_completion_style_attribute_02.js]
 [browser_markup_css_completion_style_attribute_03.js]
 [browser_markup_display_node_01.js]
 [browser_markup_display_node_02.js]
 [browser_markup_dragdrop_autoscroll_01.js]
 [browser_markup_dragdrop_autoscroll_02.js]
+[browser_markup_dragdrop_before_marker_pseudo.js]
 [browser_markup_dragdrop_distance.js]
 [browser_markup_dragdrop_draggable.js]
 [browser_markup_dragdrop_dragRootNode.js]
 [browser_markup_dragdrop_escapeKeyPress.js]
 [browser_markup_dragdrop_invalidNodes.js]
 [browser_markup_dragdrop_reorder.js]
 [browser_markup_dragdrop_tooltip.js]
 [browser_markup_events_01.js]
@@ -196,16 +197,17 @@ skip-if = verify
 [browser_markup_shadowdom.js]
 [browser_markup_shadowdom_clickreveal.js]
 [browser_markup_shadowdom_clickreveal_scroll.js]
 [browser_markup_shadowdom_copy_paths.js]
 subsuite = clipboard
 [browser_markup_shadowdom_delete.js]
 [browser_markup_shadowdom_dynamic.js]
 [browser_markup_shadowdom_hover.js]
+[browser_markup_shadowdom_marker_and_before_pseudos.js]
 [browser_markup_shadowdom_maxchildren.js]
 [browser_markup_shadowdom_mutations_shadow.js]
 [browser_markup_shadowdom_navigation.js]
 [browser_markup_shadowdom_nested_pick_inspect.js]
 [browser_markup_shadowdom_noslot.js]
 [browser_markup_shadowdom_open_debugger.js]
 skip-if = (os == 'win' && processor == 'aarch64') # bug 1533507
 [browser_markup_shadowdom_shadowroot_mode.js]
--- a/devtools/client/inspector/markup/test/browser_markup_accessibility_semantics.js
+++ b/devtools/client/inspector/markup/test/browser_markup_accessibility_semantics.js
@@ -9,28 +9,28 @@
 
 const TOP_CONTAINER_LEVEL = 3;
 
 add_task(async function() {
   const {inspector} = await openInspectorForURL(`
     data:text/html;charset=utf-8,
     <h1>foo</h1>
     <span>bar</span>
-    <ul>
-      <li></li>
-    </ul>`);
+    <dl>
+      <dt></dt>
+    </dl>`);
   const markup = inspector.markup;
   const doc = markup.doc;
   const win = doc.defaultView;
 
   const rootElt = markup.getContainer(markup._rootNode).elt;
   const bodyContainer = await getContainerForSelector("body", inspector);
   const spanContainer = await getContainerForSelector("span", inspector);
   const headerContainer = await getContainerForSelector("h1", inspector);
-  const listContainer = await getContainerForSelector("ul", inspector);
+  const listContainer = await getContainerForSelector("dl", inspector);
 
   // Focus on the tree element.
   rootElt.focus();
 
   // Test tree related semantics
   is(rootElt.getAttribute("role"), "tree",
     "Root container should have tree semantics");
   is(rootElt.getAttribute("aria-dropeffect"), "none",
@@ -66,26 +66,26 @@ add_task(async function() {
   ok(!spanContainer.tagLine.hasAttribute("aria-expanded"),
     "Non expandable tree items should not have aria-expanded attribute");
   ok(!headerContainer.tagLine.hasAttribute("aria-expanded"),
     "Non expandable tree items should not have aria-expanded attribute");
   is(listContainer.tagLine.getAttribute("aria-expanded"), "false",
     "Closed tree item should have aria-expanded unset");
 
   info("Selecting and expanding list container");
-  await selectNode("ul", inspector);
+  await selectNode("dl", inspector);
   EventUtils.synthesizeKey("VK_RIGHT", {}, win);
   await waitForMultipleChildrenUpdates(inspector);
 
   is(rootElt.getAttribute("aria-activedescendant"),
     listContainer.tagLine.getAttribute("id"),
     "Active descendant should not be set to list container tagLine");
   is(listContainer.tagLine.getAttribute("aria-expanded"), "true",
     "Open tree item should have aria-expanded set");
-  const listItemContainer = await getContainerForSelector("li", inspector);
+  const listItemContainer = await getContainerForSelector("dt", inspector);
   is(listItemContainer.tagLine.getAttribute("aria-level"),
     TOP_CONTAINER_LEVEL + 1,
     "Grand child container tagLine should have nested level up to date");
   is(listItemContainer.children.getAttribute("role"), "presentation",
     "Container with no children should have its children element ignored by " +
     "accessibility");
 
   info("Collapsing list container");
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_before_marker_pseudo.js
@@ -0,0 +1,62 @@
+/* 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 drag and dropping a node before a ::marker pseudo.
+
+const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
+
+add_task(async function() {
+  const {inspector} = await openInspectorForURL(TEST_URL);
+
+  info("Expand #list node");
+  const parentFront = await getNodeFront("#list", inspector);
+  await inspector.markup.expandNode(parentFront.parentNode());
+  await inspector.markup.expandNode(parentFront);
+  await waitForMultipleChildrenUpdates(inspector);
+
+  info("Scroll #list into view");
+  const parentContainer = await getContainerForNodeFront(parentFront, inspector);
+  parentContainer.elt.scrollIntoView(true);
+
+  info("Test placing an element before a ::marker psuedo");
+  await moveElementBeforeMarker("#last-list-child", parentFront, inspector);
+  const childNodes = await getChildrenOf(parentFront, inspector);
+  is(childNodes[0], "_moz_generated_content_marker",
+     "::marker is still the first child of #list");
+  is(childNodes[1], "last-list-child",
+     "#last-list-child is now the second child of #list");
+  is(childNodes[2], "first-list-child",
+     "#first-list-child is now the last child of #list");
+});
+
+async function moveElementBeforeMarker(selector, parentFront, inspector) {
+  info(`Placing ${selector} before its parent's ::marker`);
+
+  const container = await getContainerForSelector(selector, inspector);
+  const parentContainer = await getContainerForNodeFront(parentFront, inspector);
+  const offsetY = (parentContainer.tagLine.offsetTop +
+    parentContainer.tagLine.offsetHeight) - container.tagLine.offsetTop;
+
+  const onMutated = inspector.once("markupmutation");
+  const uiUpdate = inspector.once("inspector-updated");
+
+  await simulateNodeDragAndDrop(inspector, selector, 0, offsetY);
+
+  const mutations = await onMutated;
+  await uiUpdate;
+
+  is(mutations.length, 2, "2 mutations were received");
+}
+
+async function getChildrenOf(parentFront, {walker}) {
+  const {nodes} = await walker.children(parentFront);
+  return nodes.map(node => {
+    if (node.isMarkerPseudoElement) {
+      return node.displayName;
+    }
+    return node.id;
+  });
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_marker_and_before_pseudos.js
@@ -0,0 +1,112 @@
+/* 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";
+
+requestLongerTimeout(1);
+
+// Test a few static pages using webcomponents with ::marker and ::before
+// pseudos and check that they are displayed as expected in the markup view.
+
+const TEST_DATA = [
+  {
+    // Test that ::before on an empty shadow host is displayed when the host
+    // has a ::marker.
+    title: "::before after ::marker, empty node",
+    url: `data:text/html;charset=utf-8,
+      <style>
+        test-component { display: list-item; }
+        test-component::before { content: "before-host" }
+      </style>
+
+      <test-component></test-component>
+
+      <script>
+        'use strict';
+        customElements.define('test-component', class extends HTMLElement {
+          constructor() {
+            super();
+            let shadowRoot = this.attachShadow({mode: "#MODE#"});
+          }
+        });
+      </script>`,
+    tree: `
+      test-component
+        #shadow-root
+        ::marker
+        ::before`,
+
+  }, {
+    // Test ::before on a shadow host with content is displayed when the host
+    // has a ::marker.
+    title: "::before after ::marker, non-empty node",
+    url: `data:text/html;charset=utf-8,
+      <style>
+        test-component { display: list-item }
+        test-component::before { content: "before-host" }
+      </style>
+
+      <test-component>
+        <div class="light-dom"></div>
+      </test-component>
+
+      <script>
+        "use strict";
+        customElements.define("test-component", class extends HTMLElement {
+          constructor() {
+            super();
+            let shadowRoot = this.attachShadow({mode: "#MODE#"});
+            shadowRoot.innerHTML = "<slot>default content</slot>";
+          }
+        });
+      </script>`,
+    tree: `
+      test-component
+        #shadow-root
+          slot
+            div!slotted
+        ::marker
+        ::before
+        class="light-dom"`,
+  }, {
+    // Test just ::marker on a shadow host
+    title: "just ::marker, no ::before",
+    url: `data:text/html;charset=utf-8,
+      <style>
+        test-component { display: list-item }
+      </style>
+
+      <test-component></test-component>
+
+      <script>
+        "use strict";
+        customElements.define("test-component", class extends HTMLElement {
+          constructor() {
+            super();
+            let shadowRoot = this.attachShadow({mode: "#MODE#"});
+          }
+        });
+      </script>`,
+    tree: `
+      test-component
+        #shadow-root
+        ::marker`,
+  },
+];
+
+for (const {url, tree, title} of TEST_DATA) {
+  // Test each configuration in both open and closed modes
+  add_task(async function() {
+    info(`Testing: [${title}] in OPEN mode`);
+    const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "open"));
+    await assertMarkupViewAsTree(tree, "test-component", inspector);
+    await removeTab(tab);
+  });
+  add_task(async function() {
+    info(`Testing: [${title}] in CLOSED mode`);
+    const {inspector, tab} = await openInspectorForURL(url.replace(/#MODE#/g, "closed"));
+    await assertMarkupViewAsTree(tree, "test-component", inspector);
+    await removeTab(tab);
+  });
+}
--- a/devtools/client/inspector/markup/test/doc_markup_dragdrop.html
+++ b/devtools/client/inspector/markup/test/doc_markup_dragdrop.html
@@ -20,16 +20,22 @@ https://bugzilla.mozilla.org/show_bug.cg
   <input id="anonymousParent" /><span id="before">Before<!-- Force not-inline --></span>
   <pre id="test"><span id="firstChild">First</span><span id="middleChild">Middle</span><span id="lastChild">Last</span></pre>  <span id="after">After</span>
 
   <test-component class="test-component">
     <div slot="slot1" class="slotted1">slot1-1</div>
     <div slot="slot1" class="slotted2">slot1-2</div>
   </test-component>
 
+  <ol>
+    <li id="list"><span id="first-list-child"
+      >List item start</span><span id="last-list-child"
+      >List item end</span></li>
+  </ol>
+
   <script>
     "use strict";
     customElements.define("test-component", class extends HTMLElement {
       constructor() {
         super();
         const shadowRoot = this.attachShadow({mode: "open"});
         shadowRoot.innerHTML = '<slot class="slot1" name="slot1"></slot>';
       }
--- a/devtools/client/inspector/markup/views/read-only-editor.js
+++ b/devtools/client/inspector/markup/views/read-only-editor.js
@@ -11,17 +11,23 @@ const nodeConstants = require("devtools/
  */
 function ReadOnlyEditor(container, node) {
   this.container = container;
   this.markup = this.container.markup;
   this.buildMarkup();
 
   if (node.isPseudoElement) {
     this.tag.classList.add("theme-fg-color3");
-    this.tag.textContent = node.isBeforePseudoElement ? "::before" : "::after";
+    if (node.isMarkerPseudoElement) {
+      this.tag.textContent = "::marker";
+    } else if (node.isBeforePseudoElement) {
+      this.tag.textContent = "::before";
+    } else if (node.isAfterPseudoElement) {
+      this.tag.textContent = "::after";
+    }
   } else if (node.nodeType == nodeConstants.DOCUMENT_TYPE_NODE) {
     this.elt.classList.add("comment", "doctype");
     this.tag.textContent = node.doctypeString;
   } else if (node.isShadowRoot) {
     this.tag.textContent = `#shadow-root (${node.shadowRootMode})`;
   } else {
     this.tag.textContent = node.nodeName;
   }
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
@@ -16,26 +16,28 @@ add_task(async function() {
   const {inspector, view} = await openRuleView();
 
   await testTopLeft(inspector, view);
   await testTopRight(inspector, view);
   await testBottomRight(inspector, view);
   await testBottomLeft(inspector, view);
   await testParagraph(inspector, view);
   await testBody(inspector, view);
+  await testList(inspector, view);
 });
 
 async function testTopLeft(inspector, view) {
   const id = "#topleft";
   const rules = await assertPseudoElementRulesNumbers(id,
     inspector, view, {
       elementRulesNb: 4,
       firstLineRulesNb: 2,
       firstLetterRulesNb: 1,
       selectionRulesNb: 1,
+      markerRulesNb: 0,
       afterRulesNb: 1,
       beforeRulesNb: 2,
     }
   );
 
   const gutters = assertGutters(view);
 
   info("Make sure that clicking on the twisty hides pseudo elements");
@@ -118,16 +120,17 @@ async function testTopLeft(inspector, vi
 }
 
 async function testTopRight(inspector, view) {
   await assertPseudoElementRulesNumbers("#topright", inspector, view, {
     elementRulesNb: 4,
     firstLineRulesNb: 1,
     firstLetterRulesNb: 1,
     selectionRulesNb: 0,
+    markerRulesNb: 0,
     beforeRulesNb: 2,
     afterRulesNb: 1,
   });
 
   const gutters = assertGutters(view);
 
   const expander = gutters[0].querySelector(".ruleview-expander");
   ok(!view.element.firstChild.classList.contains("show-expandable-container"),
@@ -140,39 +143,42 @@ async function testTopRight(inspector, v
 }
 
 async function testBottomRight(inspector, view) {
   await assertPseudoElementRulesNumbers("#bottomright", inspector, view, {
     elementRulesNb: 4,
     firstLineRulesNb: 1,
     firstLetterRulesNb: 1,
     selectionRulesNb: 0,
+    markerRulesNb: 0,
     beforeRulesNb: 3,
     afterRulesNb: 1,
   });
 }
 
 async function testBottomLeft(inspector, view) {
   await assertPseudoElementRulesNumbers("#bottomleft", inspector, view, {
     elementRulesNb: 4,
     firstLineRulesNb: 1,
     firstLetterRulesNb: 1,
     selectionRulesNb: 0,
+    markerRulesNb: 0,
     beforeRulesNb: 2,
     afterRulesNb: 1,
   });
 }
 
 async function testParagraph(inspector, view) {
   const rules =
     await assertPseudoElementRulesNumbers("#bottomleft p", inspector, view, {
       elementRulesNb: 3,
       firstLineRulesNb: 1,
       firstLetterRulesNb: 1,
       selectionRulesNb: 2,
+      markerRulesNb: 0,
       beforeRulesNb: 0,
       afterRulesNb: 0,
     });
 
   assertGutters(view);
 
   const elementFirstLineRule = rules.firstLineRules[0];
   is(convertTextPropsToString(elementFirstLineRule.textProps),
@@ -192,16 +198,30 @@ async function testParagraph(inspector, 
 
 async function testBody(inspector, view) {
   await testNode("body", inspector, view);
 
   const gutters = getGutters(view);
   is(gutters.length, 0, "There are no gutter headings");
 }
 
+async function testList(inspector, view) {
+  await assertPseudoElementRulesNumbers("#list", inspector, view, {
+    elementRulesNb: 4,
+    firstLineRulesNb: 1,
+    firstLetterRulesNb: 1,
+    selectionRulesNb: 0,
+    markerRulesNb: 1,
+    beforeRulesNb: 1,
+    afterRulesNb: 1,
+  });
+
+  assertGutters(view);
+}
+
 function convertTextPropsToString(textProps) {
   return textProps.map(t => t.name + ": " + t.value).join("; ");
 }
 
 async function testNode(selector, inspector, view) {
   await selectNode(selector, inspector);
   const elementStyle = view._elementStyle;
   return elementStyle;
@@ -213,30 +233,34 @@ async function assertPseudoElementRulesN
   const rules = {
     elementRules: elementStyle.rules.filter(rule => !rule.pseudoElement),
     firstLineRules: elementStyle.rules.filter(rule =>
       rule.pseudoElement === ":first-line"),
     firstLetterRules: elementStyle.rules.filter(rule =>
       rule.pseudoElement === ":first-letter"),
     selectionRules: elementStyle.rules.filter(rule =>
       rule.pseudoElement === ":selection"),
+    markerRules: elementStyle.rules.filter(rule =>
+      rule.pseudoElement === ":marker"),
     beforeRules: elementStyle.rules.filter(rule =>
       rule.pseudoElement === ":before"),
     afterRules: elementStyle.rules.filter(rule =>
       rule.pseudoElement === ":after"),
   };
 
   is(rules.elementRules.length, ruleNbs.elementRulesNb,
      selector + " has the correct number of non pseudo element rules");
   is(rules.firstLineRules.length, ruleNbs.firstLineRulesNb,
      selector + " has the correct number of :first-line rules");
   is(rules.firstLetterRules.length, ruleNbs.firstLetterRulesNb,
      selector + " has the correct number of :first-letter rules");
   is(rules.selectionRules.length, ruleNbs.selectionRulesNb,
      selector + " has the correct number of :selection rules");
+  is(rules.markerRules.length, ruleNbs.markerRulesNb,
+     selector + " has the correct number of :marker rules");
   is(rules.beforeRules.length, ruleNbs.beforeRulesNb,
      selector + " has the correct number of :before rules");
   is(rules.afterRules.length, ruleNbs.afterRulesNb,
      selector + " has the correct number of :after rules");
 
   return rules;
 }
 
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js
@@ -21,9 +21,23 @@ add_task(async function() {
   is(beforeElement.tagName, "_moz_generated_content_before",
     "tag name is correct");
   await selectNode(beforeElement, inspector);
 
   const afterElement = children.nodes[children.nodes.length - 1];
   is(afterElement.tagName, "_moz_generated_content_after",
     "tag name is correct");
   await selectNode(afterElement, inspector);
+
+  const listNode = await getNodeFront("#list", inspector);
+  const listChildren = await inspector.markup.walker.children(listNode);
+
+  is(listChildren.nodes.length, 4, "<li> has correct number of children");
+  const markerElement = listChildren.nodes[0];
+  is(markerElement.tagName, "_moz_generated_content_marker",
+    "tag name is correct");
+  await selectNode(markerElement, inspector);
+
+  const listBeforeElement = listChildren.nodes[1];
+  is(listBeforeElement.tagName, "_moz_generated_content_before",
+    "tag name is correct");
+  await selectNode(listBeforeElement, inspector);
 });
--- a/devtools/client/inspector/rules/test/doc_pseudoelement.html
+++ b/devtools/client/inspector/rules/test/doc_pseudoelement.html
@@ -101,16 +101,20 @@ p:first-letter {
     right:0;
 }
 
 .bottomleft:before {
     bottom:0;
     left:0;
 }
 
+#list::marker {
+    color: purple;
+}
+
     </style>
   </head>
   <body>
     <h1>ruleview pseudoelement($("test"));</h1>
 
     <div id="topleft" class="box topleft">
         <p>Top Left<br />Position</p>
     </div>
@@ -122,10 +126,14 @@ p:first-letter {
     <div id="bottomright" class="box bottomright">
         <p>Bottom Right<br />Position</p>
     </div>
 
     <div id="bottomleft" class="box bottomleft">
         <p>Bottom Left<br />Position</p>
     </div>
 
+    <ol>
+        <li id="list" class="box">List element</li>
+    </ol>
+
   </body>
 </html>
--- a/devtools/client/inspector/shared/utils.js
+++ b/devtools/client/inspector/shared/utils.js
@@ -134,20 +134,25 @@ function getLongString(longStringActorPr
  * @return {String} selector of the element node.
  */
 function getSelectorFromGrip(grip) {
   const {
     attributes,
     nodeName,
     isAfterPseudoElement,
     isBeforePseudoElement,
+    isMarkerPseudoElement,
   } = grip.preview;
 
-  if (isAfterPseudoElement || isBeforePseudoElement) {
-    return `::${isAfterPseudoElement ? "after" : "before"}`;
+  if (isAfterPseudoElement) {
+    return "::after";
+  } else if (isBeforePseudoElement) {
+    return "::before";
+  } else if (isMarkerPseudoElement) {
+    return "::marker";
   }
 
   let selector = nodeName;
 
   if (attributes.id) {
     selector += `#${attributes.id}`;
   }
 
@@ -195,16 +200,17 @@ function translateNodeFrontToGrip(nodeFr
 
   return {
     actor: nodeFront.actorID,
     preview: {
       attributes: attributesMap,
       attributesLength: attributes.length,
       isAfterPseudoElement: nodeFront.isAfterPseudoElement,
       isBeforePseudoElement: nodeFront.isBeforePseudoElement,
+      isMarkerPseudoElement: nodeFront.isMarkerPseudoElement,
       // All the grid containers are assumed to be in the DOM tree.
       isConnected: true,
       // nodeName is already lowerCased in Node grips
       nodeName: nodeFront.nodeName.toLowerCase(),
       nodeType: nodeFront.nodeType,
     },
   };
 }
--- a/devtools/client/locales/en-US/aboutdebugging.ftl
+++ b/devtools/client/locales/en-US/aboutdebugging.ftl
@@ -41,16 +41,26 @@ aboutdebugging-sidebar-runtime-connectio
 
 # Text displayed in the about:debugging sidebar when no device was found.
 about-debugging-sidebar-no-devices = No devices discovered
 
 # Text displayed in buttons found in sidebar items representing remote runtimes.
 # Clicking on the button will attempt to connect to the runtime.
 about-debugging-sidebar-item-connect-button = Connect
 
+# Text displayed in buttons found in sidebar items when the runtime is connecting.
+about-debugging-sidebar-item-connect-button-connecting = Connecting…
+
+# Text displayed in buttons found in sidebar items when the connection failed.
+about-debugging-sidebar-item-connect-button-connection-failed = Connection failed
+
+# Text displayed in connection warning on sidebar item of the runtime when connecting to
+# the runtime is taking too much time.
+about-debugging-sidebar-item-connect-button-connection-not-responding = Connection still pending, check for messages on the target browser
+
 # Temporary text displayed in sidebar items representing remote runtimes after
 # successfully connecting to them. Temporary UI, do not localize.
 about-debugging-sidebar-item-connected-label = Connected
 
 # Text displayed in sidebar items for remote devices where a compatible browser (eg
 # Firefox) has not been detected yet. Typically, Android phones connected via USB with
 # USB debugging enabled, but where Firefox is not started.
 about-debugging-sidebar-runtime-item-waiting-for-browser = Waiting for browser…
--- a/devtools/client/netmonitor/src/components/HeadersPanel.js
+++ b/devtools/client/netmonitor/src/components/HeadersPanel.js
@@ -58,16 +58,20 @@ const SUMMARY_URL = L10N.getStr("netmoni
 const SUMMARY_STATUS = L10N.getStr("netmonitor.summary.status");
 const SUMMARY_VERSION = L10N.getStr("netmonitor.summary.version");
 const SUMMARY_STATUS_LEARN_MORE = L10N.getStr("netmonitor.summary.learnMore");
 const SUMMARY_REFERRER_POLICY = L10N.getStr("netmonitor.summary.referrerPolicy");
 
 /**
  * Headers panel component
  * Lists basic information about the request
+ *
+ * In http/2 all response headers are in small case.
+ * See: https://developer.mozilla.org/en-US/docs/Tools/Network_Monitor/request_details#Headers
+ * RFC: https://tools.ietf.org/html/rfc7540#section-8.1.2
  */
 class HeadersPanel extends Component {
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       cloneSelectedRequest: PropTypes.func.isRequired,
       member: PropTypes.object,
       request: PropTypes.object.isRequired,
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -182,17 +182,16 @@ skip-if = os == 'win' # bug 1391264
 [browser_net_security-tab-deselect.js]
 [browser_net_security-tab-visibility.js]
 [browser_net_security-warnings.js]
 [browser_net_send-beacon.js]
 [browser_net_send-beacon-other-tab.js]
 [browser_net_set-cookie-same-site.js]
 [browser_net_simple-request-data.js]
 [browser_net_simple-request-details.js]
-skip-if = true # Bug 1258809
 [browser_net_simple-request.js]
 [browser_net_sort-01.js]
 [browser_net_sort-02.js]
 [browser_net_sort-reset.js]
 [browser_net_statistics-01.js]
 skip-if = true # Bug 1373558
 [browser_net_statistics-02.js]
 [browser_net_status-bar-transferred-size.js]
--- a/devtools/client/netmonitor/test/browser_net_simple-request-details.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-details.js
@@ -8,265 +8,248 @@
  */
 
 add_task(async function() {
   const { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
 
   const { tab, monitor } = await initNetMonitor(SIMPLE_SJS);
   info("Starting test... ");
 
-  const { document, store, windowRequire, NetMonitorView } = monitor.panelWin;
+  const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
-  const { EVENTS } = windowRequire("devtools/client/netmonitor/src/constants");
+  const { PANELS } = windowRequire("devtools/client/netmonitor/src/constants");
   const {
     getSelectedRequest,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
-  const Editor = require("devtools/client/shared/sourceeditor/editor");
 
   store.dispatch(Actions.batchEnable(false));
 
   const wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
   await wait;
 
   is(getSelectedRequest(store.getState()), undefined,
     "There shouldn't be any selected item in the requests menu.");
   is(store.getState().requests.requests.size, 1,
     "The requests menu should not be empty after the first request.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after first request.");
 
+  const waitForHeaders = waitForDOM(document, ".headers-overview");
+
   store.dispatch(Actions.toggleNetworkDetails());
 
   isnot(getSelectedRequest(store.getState()), undefined,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should not be hidden after toggle button was pressed.");
 
-  testHeadersTab();
+  await waitForHeaders;
+
+  await testHeadersTab();
   await testCookiesTab();
-  testParamsTab();
+  await testParamsTab();
   await testResponseTab();
-  testTimingsTab();
+  await testTimingsTab();
   return teardown(monitor);
 
   function getSelectedIndex(state) {
     if (!state.requests.selectedId) {
       return -1;
     }
     return getSortedRequests(state).findIndex(r => r.id === state.requests.selectedId);
   }
 
-  function testHeadersTab() {
-    const tabEl = document.querySelectorAll("#details-pane tab")[0];
-    const tabpanel = document.querySelectorAll("#details-pane tabpanel")[0];
-
-    is(tabEl.getAttribute("selected"), "true",
-      "The headers tab in the network details pane should be selected.");
+  async function testHeadersTab() {
+    const tabEl = document.querySelectorAll(".network-details-panel .tabs-menu a")[0];
+    const tabpanel = document.querySelector(".network-details-panel .tab-panel");
 
-    is(tabpanel.querySelector("#headers-summary-url-value").getAttribute("value"),
+    is(tabEl.getAttribute("aria-selected"), "true",
+      "The headers tab in the network details pane should be selected.");
+    // Request URL
+    is(tabpanel.querySelectorAll(".tabpanel-summary-value")[0].innerText,
       SIMPLE_SJS, "The url summary value is incorrect.");
-    is(tabpanel.querySelector("#headers-summary-url-value").getAttribute("tooltiptext"),
-      SIMPLE_SJS, "The url summary tooltiptext is incorrect.");
-    is(tabpanel.querySelector("#headers-summary-method-value").getAttribute("value"),
+    // Request method
+    is(tabpanel.querySelectorAll(".tabpanel-summary-value")[1].innerText,
       "GET", "The method summary value is incorrect.");
-    is(tabpanel.querySelector("#headers-summary-address-value").getAttribute("value"),
+    // Remote address
+    is(tabpanel.querySelectorAll(".tabpanel-summary-value")[2].innerText,
       "127.0.0.1:8888", "The remote address summary value is incorrect.");
-    is(tabpanel.querySelector("#headers-summary-status-circle").getAttribute("data-code"),
+    // Status code
+    is(tabpanel.querySelector(".requests-list-status-code").innerText,
       "200", "The status summary code is incorrect.");
-    is(tabpanel.querySelector("#headers-summary-status-value").getAttribute("value"),
-      "200 Och Aye", "The status summary value is incorrect.");
+    is(tabpanel.querySelector(".status-text").getAttribute("value"),
+      "Och Aye", "The status summary value is incorrect.");
+    // Version
+    is(tabpanel.querySelectorAll(".tabpanel-summary-value")[4].innerText,
+    "HTTP/1.1", "The HTTP version is incorrect.");
 
-    is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
-      "There should be 2 header scopes displayed in this tabpanel.");
-    is(tabpanel.querySelectorAll(".variable-or-property").length, 19,
-      "There should be 19 header values displayed in this tabpanel.");
+    await waitForRequestData(store, ["requestHeaders", "responseHeaders"]);
 
-    is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
-      "The empty notice should not be displayed in this tabpanel.");
+    is(tabpanel.querySelectorAll(".treeTable tbody .tree-section").length, 2,
+      "There should be 2 header scopes displayed in this tabpanel.");
+
+    is(tabpanel.querySelectorAll(":not(.tree-section) > .treeLabelCell").length,
+      23, "There should be 23 header values displayed in this tabpanel.");
 
-    const responseScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
-    const requestScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
+    const headersTable = tabpanel.querySelector(".treeTable tbody");
+    const responseScope = headersTable.querySelectorAll("tr[id^='/Response headers']");
+    const requestScope = headersTable.querySelectorAll("tr[id^='/Request headers']");
 
-    is(responseScope.querySelector(".name").getAttribute("value"),
-      L10N.getStr("responseHeaders") + " (" +
-      L10N.getFormatStr("networkMenu.sizeKB",
-        L10N.numberWithDecimals(330 / 1024, 3)) + ")",
+    ok(headersTable.querySelectorAll(".tree-section .treeLabel")[0].innerHTML
+      .match(new RegExp(L10N.getStr("responseHeaders") + " \\([0-9]+ .+\\)")),
       "The response headers scope doesn't have the correct title.");
 
-    ok(requestScope.querySelector(".name").getAttribute("value").includes(
-      L10N.getStr("requestHeaders") + " (0"),
+    ok(headersTable.querySelectorAll(".tree-section .treeLabel")[1].innerHTML.includes(
+      L10N.getStr("requestHeaders") + " ("),
       "The request headers scope doesn't have the correct title.");
-    // Can't test for full request headers title because the size may
-    // vary across platforms ("User-Agent" header differs). We're pretty
-    // sure it's smaller than 1 MB though, so it starts with a 0.
 
-    is(responseScope.querySelectorAll(".variables-view-variable .name")[0]
-      .getAttribute("value"),
-      "Cache-Control", "The first response header name was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .value")[0]
-      .getAttribute("value"),
-      "\"no-cache, no-store, must-revalidate\"",
-      "The first response header value was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .name")[1]
-      .getAttribute("value"),
-      "Connection", "The second response header name was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .value")[1]
-      .getAttribute("value"),
-      "\"close\"", "The second response header value was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .name")[2]
-      .getAttribute("value"),
-      "Content-Length", "The third response header name was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .value")[2]
-      .getAttribute("value"),
-      "\"12\"", "The third response header value was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .name")[3]
-      .getAttribute("value"),
-      "Content-Type", "The fourth response header name was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .value")[3]
-      .getAttribute("value"),
-      "\"text/plain; charset=utf-8\"", "The fourth response header value was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .name")[9]
-      .getAttribute("value"),
-      "foo-bar", "The last response header name was incorrect.");
-    is(responseScope.querySelectorAll(".variables-view-variable .value")[9]
-      .getAttribute("value"),
-      "\"baz\"", "The last response header value was incorrect.");
+    const responseHeaders = [
+      {
+        name: "cache-control",
+        value: "no-cache, no-store, must-revalidate",
+        pos: "first",
+        index: 1,
+      },
+      {
+        name: "connection",
+        value: "close",
+        pos: "second",
+        index: 2,
+      },
+      {
+        name: "content-length",
+        value: "12",
+        pos: "third",
+        index: 3,
+      },
+      {
+        name: "content-type",
+        value: "text/plain; charset=utf-8",
+        pos: "fourth",
+        index: 4,
+      },
+      {
+        name: "foo-bar",
+        value: "baz",
+        pos: "seventh",
+        index: 7,
+      },
+    ];
+    responseHeaders.forEach((header) => {
+      is(responseScope[header.index].querySelector(".treeLabel").innerHTML,
+        header.name, `The ${header.pos} response header name was incorrect.`);
+      is(responseScope[header.index].querySelector(".objectBox").innerHTML,
+        header.value, `The ${header.pos} response header value was incorrect.`);
+    });
 
-    is(requestScope.querySelectorAll(".variables-view-variable .name")[0]
-      .getAttribute("value"),
-      "Host", "The first request header name was incorrect.");
-    is(requestScope.querySelectorAll(".variables-view-variable .value")[0]
-      .getAttribute("value"),
-      "\"example.com\"", "The first request header value was incorrect.");
-    is(requestScope.querySelectorAll(".variables-view-variable .name")[6]
-      .getAttribute("value"),
-      "Connection", "The ante-penultimate request header name was incorrect.");
-    is(requestScope.querySelectorAll(".variables-view-variable .value")[6]
-      .getAttribute("value"),
-      "\"keep-alive\"", "The ante-penultimate request header value was incorrect.");
-    is(requestScope.querySelectorAll(".variables-view-variable .name")[7]
-      .getAttribute("value"),
-      "Pragma", "The penultimate request header name was incorrect.");
-    is(requestScope.querySelectorAll(".variables-view-variable .value")[7]
-      .getAttribute("value"),
-      "\"no-cache\"", "The penultimate request header value was incorrect.");
-    is(requestScope.querySelectorAll(".variables-view-variable .name")[8]
-      .getAttribute("value"),
-      "Cache-Control", "The last request header name was incorrect.");
-    is(requestScope.querySelectorAll(".variables-view-variable .value")[8]
-      .getAttribute("value"),
-      "\"no-cache\"", "The last request header value was incorrect.");
+    const requestHeaders = [
+      {
+        name: "Cache-Control",
+        value: "no-cache",
+        pos: "fourth",
+        index: 4,
+      },
+      {
+        name: "Connection",
+        value: "keep-alive",
+        pos: "fifth",
+        index: 5,
+      },
+      {
+        name: "Host",
+        value: "example.com",
+        pos: "seventh",
+        index: 7,
+      },
+      {
+        name: "Pragma",
+        value: "no-cache",
+        pos: "eighth",
+        index: 8,
+      },
+    ];
+    requestHeaders.forEach((header) => {
+      is(requestScope[header.index].querySelector(".treeLabel").innerHTML,
+        header.name, `The ${header.pos} request header name was incorrect.`);
+      is(requestScope[header.index].querySelector(".objectBox").innerHTML,
+        header.value, `The ${header.pos} request header value was incorrect.`);
+    });
   }
 
   async function testCookiesTab() {
-    const onEvent = monitor.panelWin.api.once(EVENTS.TAB_UPDATED);
-    EventUtils.sendMouseEvent({ type: "mousedown" },
-      document.querySelectorAll("#details-pane tab")[1]);
-    await onEvent;
-
-    const tabEl = document.querySelectorAll("#details-pane tab")[1];
-    const tabpanel = document.querySelectorAll("#details-pane tabpanel")[1];
+    const tabpanel = await selectTab(PANELS.COOKIES, 1);
 
-    is(tabEl.getAttribute("selected"), "true",
-      "The cookies tab in the network details pane should be selected.");
-
-    is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
+    const cookieTable = tabpanel.querySelector(".treeTable tbody");
+    is(cookieTable.querySelectorAll(".tree-section").length, 2,
       "There should be 2 cookie scopes displayed in this tabpanel.");
-    is(tabpanel.querySelectorAll(".variable-or-property").length, 6,
-      "There should be 6 cookie values displayed in this tabpanel.");
+    // 2 Cookies in response - 1 httpOnly and 1 value for each cookie - total 6
+    is(cookieTable.querySelectorAll("tr[id^='/Response cookies/'").length, 6,
+      "There should be 6 rows displayed in response cookies table");
+    is(cookieTable.querySelectorAll("tr[id^='/Request cookies/'").length, 2,
+      "There should be 2 cookie values displayed in request cookies table.");
   }
 
-  function testParamsTab() {
-    EventUtils.sendMouseEvent({ type: "mousedown" },
-      document.querySelectorAll("#details-pane tab")[2]);
+  async function testParamsTab() {
+    const tabpanel = await selectTab(PANELS.PARAMS, 2);
 
-    const tabEl = document.querySelectorAll("#details-pane tab")[2];
-    const tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
-
-    is(tabEl.getAttribute("selected"), "true",
-      "The params tab in the network details pane should be selected.");
-
-    is(tabpanel.querySelectorAll(".variables-view-scope").length, 0,
+    is(tabpanel.querySelectorAll(".panel-container").length, 0,
       "There should be no param scopes displayed in this tabpanel.");
-    is(tabpanel.querySelectorAll(".variable-or-property").length, 0,
-      "There should be no param values displayed in this tabpanel.");
-    is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 1,
+    is(tabpanel.querySelectorAll(".empty-notice").length, 1,
       "The empty notice should be displayed in this tabpanel.");
-
-    is(tabpanel.querySelector("#request-params-box")
-      .hasAttribute("hidden"), false,
-      "The request params box should not be hidden.");
-    is(tabpanel.querySelector("#request-post-data-textarea-box")
-      .hasAttribute("hidden"), true,
-      "The request post data textarea box should be hidden.");
   }
 
   async function testResponseTab() {
-    const onEvent = monitor.panelWin.api.once(EVENTS.TAB_UPDATED);
-    EventUtils.sendMouseEvent({ type: "mousedown" },
-      document.querySelectorAll("#details-pane tab")[3]);
-    await onEvent;
-
-    const tabEl = document.querySelectorAll("#details-pane tab")[3];
-    const tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
-
-    is(tabEl.getAttribute("selected"), "true",
-      "The response tab in the network details pane should be selected.");
+    const tabpanel = await selectTab(PANELS.RESPONSE, 3);
+    await waitForDOM(document, ".treeTable tbody");
 
-    is(tabpanel.querySelector("#response-content-info-header")
-      .hasAttribute("hidden"), true,
-      "The response info header should be hidden.");
-    is(tabpanel.querySelector("#response-content-json-box")
-      .hasAttribute("hidden"), true,
-      "The response content json box should be hidden.");
-    is(tabpanel.querySelector("#response-content-textarea-box")
-      .hasAttribute("hidden"), false,
-      "The response content textarea box should not be hidden.");
-    is(tabpanel.querySelector("#response-content-image-box")
-      .hasAttribute("hidden"), true,
-      "The response content image box should be hidden.");
-
-    const editor = await NetMonitorView.editor("#response-content-textarea");
-    is(editor.getText(), "Hello world!",
-      "The text shown in the source editor is incorrect.");
-    is(editor.getMode(), Editor.modes.text,
-      "The mode active in the source editor is incorrect.");
+    const responseTable = tabpanel.querySelector(".treeTable tbody");
+    is(responseTable.querySelectorAll(".tree-section").length, 1,
+      "There should be 1 response scope displayed in this tabpanel.");
+    is(responseTable.querySelectorAll(".editor-row-container").length, 1,
+      "The response payload tab should be open initially.");
   }
 
-  function testTimingsTab() {
-    EventUtils.sendMouseEvent({ type: "mousedown" },
-      document.querySelectorAll("#details-pane tab")[4]);
-
-    const tabEl = document.querySelectorAll("#details-pane tab")[4];
-    const tabpanel = document.querySelectorAll("#details-pane tabpanel")[4];
+  async function testTimingsTab() {
+    const tabpanel = await selectTab(PANELS.TIMINGS, 4);
 
-    is(tabEl.getAttribute("selected"), "true",
-      "The timings tab in the network details pane should be selected.");
-
-    ok(tabpanel.querySelector("#timings-summary-blocked .requests-list-timings-total")
-      .getAttribute("value").match(/[0-9]+/),
-      "The blocked timing info does not appear to be correct.");
+    const displayFormat = new RegExp(/[0-9]+ ms$/);
+    const propsToVerify = [
+      "blocked",
+      "dns",
+      "connect",
+      "ssl",
+      "send",
+      "wait",
+      "receive",
+    ];
 
-    ok(tabpanel.querySelector("#timings-summary-dns .requests-list-timings-total")
-      .getAttribute("value").match(/[0-9]+/),
-      "The dns timing info does not appear to be correct.");
-
-    ok(tabpanel.querySelector("#timings-summary-connect .requests-list-timings-total")
-      .getAttribute("value").match(/[0-9]+/),
-      "The connect timing info does not appear to be correct.");
+    // To ensure that test case for a new property is written, otherwise this
+    // test will fail
+    is(tabpanel.querySelectorAll(".tabpanel-summary-container").length,
+      propsToVerify.length,
+      `There should be exactly ${propsToVerify.length} values
+      displayed in this tabpanel`);
 
-    ok(tabpanel.querySelector("#timings-summary-send .requests-list-timings-total")
-      .getAttribute("value").match(/[0-9]+/),
-      "The send timing info does not appear to be correct.");
+    propsToVerify.forEach((propName) => {
+      ok(tabpanel.querySelector(`#timings-summary-${propName}
+      .requests-list-timings-total`)
+        .innerHTML.match(displayFormat),
+        `The ${propName} timing info does not appear to be correct.`);
+    });
+  }
 
-    ok(tabpanel.querySelector("#timings-summary-wait .requests-list-timings-total")
-      .getAttribute("value").match(/[0-9]+/),
-      "The wait timing info does not appear to be correct.");
+  async function selectTab(tabName, pos) {
+    const tabEl = document.querySelectorAll(".network-details-panel .tabs-menu a")[pos];
 
-    ok(tabpanel.querySelector("#timings-summary-receive .requests-list-timings-total")
-      .getAttribute("value").match(/[0-9]+/),
-      "The receive timing info does not appear to be correct.");
+    const onPanelOpen = waitForDOM(document, `#${tabName}-panel`);
+    EventUtils.sendMouseEvent({ type: "click" }, tabEl);
+    await onPanelOpen;
+
+    is(tabEl.getAttribute("aria-selected"), "true",
+      `The ${tabName} tab in the network details pane should be selected.`);
+
+    return document.querySelector(".network-details-panel .tab-panel");
   }
 });
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -6277,24 +6277,33 @@ function ElementNode(props) {
   return span(baseConfig, ...elements, inspectIcon);
 }
 
 function getElements(grip, mode) {
   const {
     attributes,
     nodeName,
     isAfterPseudoElement,
-    isBeforePseudoElement
+    isBeforePseudoElement,
+    isMarkerPseudoElement
   } = grip.preview;
   const nodeNameElement = span({
     className: "tag-name"
   }, nodeName);
 
-  if (isAfterPseudoElement || isBeforePseudoElement) {
-    return [span({ className: "attrName" }, `::${isAfterPseudoElement ? "after" : "before"}`)];
+  let pseudoNodeName;
+  if (isAfterPseudoElement) {
+    pseudoNodeName = "after";
+  } else if (isBeforePseudoElement) {
+    pseudoNodeName = "before";
+  } else if (isMarkerPseudoElement) {
+    pseudoNodeName = "marker";
+  }
+  if (pseudoNodeName) {
+    return [span({ className: "attrName" }, `::${pseudoNodeName}`)];
   }
 
   if (mode === MODE.TINY) {
     const elements = [nodeNameElement];
     if (attributes.id) {
       elements.push(span({ className: "attrName" }, `#${attributes.id}`));
     }
     if (attributes.class) {
--- a/devtools/client/webconsole/components/ConsoleOutput.js
+++ b/devtools/client/webconsole/components/ConsoleOutput.js
@@ -56,17 +56,17 @@ class ConsoleOutput extends Component {
         openContextMenu: PropTypes.func.isRequired,
         sourceMapService: PropTypes.object,
       }),
       dispatch: PropTypes.func.isRequired,
       timestampsVisible: PropTypes.bool,
       messagesTableData: PropTypes.object.isRequired,
       messagesRepeat: PropTypes.object.isRequired,
       warningGroups: PropTypes.object.isRequired,
-      isInWarningGroup: PropTypes.isRequired,
+      isInWarningGroup: PropTypes.func,
       networkMessagesUpdate: PropTypes.object.isRequired,
       visibleMessages: PropTypes.array.isRequired,
       networkMessageActiveTabId: PropTypes.string.isRequired,
       onFirstMeaningfulPaint: PropTypes.func.isRequired,
       pausedExecutionPoint: PropTypes.any,
     };
   }
 
--- a/devtools/server/actors/inspector/css-logic.js
+++ b/devtools/server/actors/inspector/css-logic.js
@@ -660,17 +660,17 @@ CssLogic.getSelectors = function(domRule
 /**
  * Given a node, check to see if it is a ::before or ::after element.
  * If so, return the node that is accessible from within the document
  * (the parent of the anonymous node), along with which pseudo element
  * it was.  Otherwise, return the node itself.
  *
  * @returns {Object}
  *            - {DOMNode} node The non-anonymous node
- *            - {string} pseudo One of ':before', ':after', or null.
+ *            - {string} pseudo One of ':marker', ':before', ':after', or null.
  */
 CssLogic.getBindingElementAndPseudo = getBindingElementAndPseudo;
 
 /**
  * Get the computed style on a node.  Automatically handles reading
  * computed styles on a ::before/::after element by reading on the
  * parent node with the proper pseudo argument.
  *
--- a/devtools/server/actors/inspector/event-collector.js
+++ b/devtools/server/actors/inspector/event-collector.js
@@ -7,16 +7,17 @@
 
 "use strict";
 
 const { Cu } = require("chrome");
 const Services = require("Services");
 const {
   isAfterPseudoElement,
   isBeforePseudoElement,
+  isMarkerPseudoElement,
   isNativeAnonymous,
 } = require("devtools/shared/layout/utils");
 const Debugger = require("Debugger");
 
 // eslint-disable-next-line
 const JQUERY_LIVE_REGEX = /return typeof \w+.*.event\.triggered[\s\S]*\.event\.(dispatch|handle).*arguments/;
 
 const REACT_EVENT_NAMES = [
@@ -384,17 +385,17 @@ class DOMEventCollector extends MainEven
  */
 class JQueryEventCollector extends MainEventCollector {
   getListeners(node, {checkOnly} = {}) {
     const jQuery = this.getJQuery(node);
     const handlers = [];
 
     // If jQuery is not on the page, if this is an anonymous node or a pseudo
     // element we need to return early.
-    if (!jQuery || isNativeAnonymous(node) ||
+    if (!jQuery || isNativeAnonymous(node) || isMarkerPseudoElement(node) ||
         isBeforePseudoElement(node) || isAfterPseudoElement(node)) {
       if (checkOnly) {
         return false;
       }
       return handlers;
     }
 
     let eventsObj = null;
--- a/devtools/server/actors/inspector/node.js
+++ b/devtools/server/actors/inspector/node.js
@@ -13,16 +13,17 @@ const { nodeSpec, nodeListSpec } = requi
 loader.lazyRequireGetter(this, "getCssPath", "devtools/shared/inspector/css-logic", true);
 loader.lazyRequireGetter(this, "getXPath", "devtools/shared/inspector/css-logic", true);
 loader.lazyRequireGetter(this, "findCssSelector", "devtools/shared/inspector/css-logic", true);
 
 loader.lazyRequireGetter(this, "isAfterPseudoElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isAnonymous", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isBeforePseudoElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isDirectShadowHostChild", "devtools/shared/layout/utils", true);
+loader.lazyRequireGetter(this, "isMarkerPseudoElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isNativeAnonymous", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isShadowAnonymous", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isShadowHost", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isShadowRoot", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "getShadowRootMode", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isXBLAnonymous", "devtools/shared/layout/utils", true);
 
 loader.lazyRequireGetter(this, "InspectorActorUtils", "devtools/server/actors/inspector/utils");
@@ -122,16 +123,17 @@ const NodeActor = protocol.ActorClassWit
 
       // doctype attributes
       name: this.rawNode.name,
       publicId: this.rawNode.publicId,
       systemId: this.rawNode.systemId,
 
       attrs: this.writeAttrs(),
       customElementLocation: this.getCustomElementLocation(),
+      isMarkerPseudoElement: isMarkerPseudoElement(this.rawNode),
       isBeforePseudoElement: isBeforePseudoElement(this.rawNode),
       isAfterPseudoElement: isAfterPseudoElement(this.rawNode),
       isAnonymous: isAnonymous(this.rawNode),
       isNativeAnonymous: isNativeAnonymous(this.rawNode),
       isXBLAnonymous: isXBLAnonymous(this.rawNode),
       isShadowAnonymous: isShadowAnonymous(this.rawNode),
       isShadowRoot: shadowRoot,
       shadowRootMode: getShadowRootMode(this.rawNode),
@@ -181,17 +183,19 @@ const NodeActor = protocol.ActorClassWit
     this.rawNode.addEventListener("slotchange", this.slotchangeListener);
   },
 
   // Estimate the number of children that the walker will return without making
   // a call to children() if possible.
   get numChildren() {
     // For pseudo elements, childNodes.length returns 1, but the walker
     // will return 0.
-    if (isBeforePseudoElement(this.rawNode) || isAfterPseudoElement(this.rawNode)) {
+    if (isMarkerPseudoElement(this.rawNode) ||
+      isBeforePseudoElement(this.rawNode) || isAfterPseudoElement(this.rawNode)
+    ) {
       return 0;
     }
 
     const rawNode = this.rawNode;
     let numChildren = rawNode.childNodes.length;
     const hasAnonChildren = rawNode.nodeType === Node.ELEMENT_NODE &&
                           rawNode.ownerDocument.getAnonymousNodes(rawNode);
 
--- a/devtools/server/actors/inspector/utils.js
+++ b/devtools/server/actors/inspector/utils.js
@@ -55,23 +55,24 @@ function isInXULDocument(el) {
   const doc = nodeDocument(el);
   return doc &&
          doc.documentElement &&
          doc.documentElement.namespaceURI === XUL_NS;
 }
 
 /**
  * This DeepTreeWalker filter skips whitespace text nodes and anonymous
- * content with the exception of ::before and ::after and anonymous content
- * in XUL document (needed to show all elements in the browser toolbox).
+ * content with the exception of ::marker, ::before, and ::after, plus anonymous
+ * content in XUL document (needed to show all elements in the browser toolbox).
  */
 function standardTreeWalkerFilter(node) {
-  // ::before and ::after are native anonymous content, but we always
+  // ::marker, ::before, and ::after are native anonymous content, but we always
   // want to show them
-  if (node.nodeName === "_moz_generated_content_before" ||
+  if (node.nodeName === "_moz_generated_content_marker" ||
+      node.nodeName === "_moz_generated_content_before" ||
       node.nodeName === "_moz_generated_content_after") {
     return nodeFilterConstants.FILTER_ACCEPT;
   }
 
   // Ignore empty whitespace text nodes that do not impact the layout.
   if (isWhitespaceTextNode(node)) {
     return nodeHasSize(node)
            ? nodeFilterConstants.FILTER_ACCEPT
--- a/devtools/server/actors/inspector/walker.js
+++ b/devtools/server/actors/inspector/walker.js
@@ -12,16 +12,17 @@ const {walkerSpec} = require("devtools/s
 const {LongStringActor} = require("devtools/server/actors/string");
 const InspectorUtils = require("InspectorUtils");
 
 loader.lazyRequireGetter(this, "getFrameElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isAfterPseudoElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isAnonymous", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isBeforePseudoElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isDirectShadowHostChild", "devtools/shared/layout/utils", true);
+loader.lazyRequireGetter(this, "isMarkerPseudoElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isNativeAnonymous", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isShadowHost", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isShadowRoot", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isTemplateElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "loadSheet", "devtools/shared/layout/utils", true);
 
 loader.lazyRequireGetter(this, "throttle", "devtools/shared/throttle", true);
 
@@ -82,16 +83,17 @@ const PSEUDO_SELECTORS = [
   [":last-child", 2],
   [":root", 0],
   [":empty", 0],
   [":target", 0],
   [":enabled", 0],
   [":disabled", 0],
   [":checked", 1],
   ["::selection", 0],
+  ["::marker", 0],
 ];
 
 const HELPER_SHEET = "data:text/css;charset=utf-8," + encodeURIComponent(`
   .__fx-devtools-hide-shortcut__ {
     visibility: hidden !important;
   }
 
   :-moz-devtools-highlighted {
@@ -531,17 +533,18 @@ var WalkerActor = protocol.ActorClassWit
   /**
    * If the given NodeActor only has a single text node as a child with a text
    * content small enough to be inlined, return that child's NodeActor.
    *
    * @param NodeActor node
    */
   inlineTextChild: function({ rawNode }) {
     // Quick checks to prevent creating a new walker if possible.
-    if (isBeforePseudoElement(rawNode) ||
+    if (isMarkerPseudoElement(rawNode) ||
+        isBeforePseudoElement(rawNode) ||
         isAfterPseudoElement(rawNode) ||
         isShadowHost(rawNode) ||
         rawNode.nodeType != Node.ELEMENT_NODE ||
         rawNode.children.length > 0) {
       return undefined;
     }
 
     const walker = this.getDocumentWalker(rawNode);
@@ -860,30 +863,36 @@ var WalkerActor = protocol.ActorClassWit
       hasLast = nodes[nodes.length - 1] == lastChild;
     } else {
       // If nodes is still an empty array, we are on a host element with a shadow root but
       // no direct children.
       hasFirst = hasLast = true;
     }
 
     if (shadowHost) {
-      // Use anonymous walkers to fetch ::before / ::after pseudo elements
+      // Use anonymous walkers to fetch ::marker / ::before / ::after pseudo
+      // elements
       const firstChildWalker = this.getDocumentWalker(node.rawNode);
       const first = firstChildWalker.firstChild();
-      const hasBefore = first && first.nodeName === "_moz_generated_content_before";
+      const hasMarker = first && first.nodeName === "_moz_generated_content_marker";
+      const maybeBeforeNode = hasMarker ? firstChildWalker.nextSibling() : first;
+      const hasBefore = maybeBeforeNode &&
+        maybeBeforeNode.nodeName === "_moz_generated_content_before";
 
       const lastChildWalker = this.getDocumentWalker(node.rawNode);
       const last = lastChildWalker.lastChild();
       const hasAfter = last && last.nodeName === "_moz_generated_content_after";
 
       nodes = [
         // #shadow-root
         ...(hideShadowRoot ? [] : [node.rawNode.openOrClosedShadowRoot]),
+        // ::marker
+        ...(hasMarker ? [first] : []),
         // ::before
-        ...(hasBefore ? [first] : []),
+        ...(hasBefore ? [maybeBeforeNode] : []),
         // shadow host direct children
         ...nodes,
         // native anonymous content for UA widgets
         ...(showNativeAnonymousChildren ?
           this.getNativeAnonymousChildren(node.rawNode) : []),
         // ::after
         ...(hasAfter ? [last] : []),
       ];
--- a/devtools/server/actors/utils/walker-search.js
+++ b/devtools/server/actors/utils/walker-search.js
@@ -88,17 +88,20 @@ WalkerIndex.prototype = {
     const documentWalker = this.walker.getDocumentWalker(this.doc);
     while (documentWalker.nextNode()) {
       const node = documentWalker.currentNode;
 
       if (node.nodeType === 1) {
         // For each element node, we get the tagname and all attributes names
         // and values
         const localName = node.localName;
-        if (localName === "_moz_generated_content_before") {
+        if (localName === "_moz_generated_content_marker") {
+          this._addToIndex("tag", node, "::marker");
+          this._addToIndex("text", node, node.textContent.trim());
+        } else if (localName === "_moz_generated_content_before") {
           this._addToIndex("tag", node, "::before");
           this._addToIndex("text", node, node.textContent.trim());
         } else if (localName === "_moz_generated_content_after") {
           this._addToIndex("tag", node, "::after");
           this._addToIndex("text", node, node.textContent.trim());
         } else {
           this._addToIndex("tag", node, node.localName);
         }
--- a/devtools/shared/fronts/node.js
+++ b/devtools/shared/fronts/node.js
@@ -262,24 +262,28 @@ class NodeFront extends FrontClassWithSp
   }
   get numChildren() {
     return this._form.numChildren;
   }
   get hasEventListeners() {
     return this._form.hasEventListeners;
   }
 
+  get isMarkerPseudoElement() {
+    return this._form.isMarkerPseudoElement;
+  }
   get isBeforePseudoElement() {
     return this._form.isBeforePseudoElement;
   }
   get isAfterPseudoElement() {
     return this._form.isAfterPseudoElement;
   }
   get isPseudoElement() {
-    return this.isBeforePseudoElement || this.isAfterPseudoElement;
+    return this.isBeforePseudoElement || this.isAfterPseudoElement ||
+      this.isMarkerPseudoElement;
   }
   get isAnonymous() {
     return this._form.isAnonymous;
   }
   get isInHTMLDocument() {
     return this._form.isInHTMLDocument;
   }
   get tagName() {
--- a/devtools/shared/inspector/css-logic.js
+++ b/devtools/shared/inspector/css-logic.js
@@ -451,29 +451,32 @@ exports.getCssPath = getCssPath;
 /**
  * Get the xpath for a given element.
  * @param {DomNode} ele
  * @returns a string that can be used as an XPath to find the element uniquely.
  */
 exports.getXPath = getXPath;
 
 /**
- * Given a node, check to see if it is a ::before or ::after element.
+ * Given a node, check to see if it is a ::marker, ::before, or ::after element.
  * If so, return the node that is accessible from within the document
  * (the parent of the anonymous node), along with which pseudo element
  * it was.  Otherwise, return the node itself.
  *
  * @returns {Object}
  *            - {DOMNode} node The non-anonymous node
- *            - {string} pseudo One of ':before', ':after', or null.
+ *            - {string} pseudo One of ':marker', ':before', ':after', or null.
  */
 function getBindingElementAndPseudo(node) {
   let bindingElement = node;
   let pseudo = null;
-  if (node.nodeName == "_moz_generated_content_before") {
+  if (node.nodeName == "_moz_generated_content_marker") {
+    bindingElement = node.parentNode;
+    pseudo = ":marker";
+  } else if (node.nodeName == "_moz_generated_content_before") {
     bindingElement = node.parentNode;
     pseudo = ":before";
   } else if (node.nodeName == "_moz_generated_content_after") {
     bindingElement = node.parentNode;
     pseudo = ":after";
   }
   return {
     bindingElement: bindingElement,
--- a/devtools/shared/layout/utils.js
+++ b/devtools/shared/layout/utils.js
@@ -633,28 +633,40 @@ exports.isShadowHost = isShadowHost;
  * still considered to be the "host" element, and we need to walk them differently.
  *
  * @param {DOMNode} node
  * @return {Boolean}
  */
 function isDirectShadowHostChild(node) {
   // Pseudo elements and native anonymous elements are always part of the anonymous tree.
   if (
+    isMarkerPseudoElement(node) ||
     isBeforePseudoElement(node) ||
     isAfterPseudoElement(node) ||
     isNativeAnonymous(node)) {
     return false;
   }
 
   const parentNode = node.parentNode;
   return parentNode && !!parentNode.openOrClosedShadowRoot;
 }
 exports.isDirectShadowHostChild = isDirectShadowHostChild;
 
 /**
+ * Determine whether a node is a ::marker pseudo.
+ *
+ * @param {DOMNode} node
+ * @return {Boolean}
+ */
+function isMarkerPseudoElement(node) {
+  return node.nodeName === "_moz_generated_content_marker";
+}
+exports.isMarkerPseudoElement = isMarkerPseudoElement;
+
+/**
  * Determine whether a node is a ::before pseudo.
  *
  * @param {DOMNode} node
  * @return {Boolean}
  */
 function isBeforePseudoElement(node) {
   return node.nodeName === "_moz_generated_content_before";
 }
--- a/dom/media/platforms/agnostic/DAV1DDecoder.cpp
+++ b/dom/media/platforms/agnostic/DAV1DDecoder.cpp
@@ -57,29 +57,34 @@ RefPtr<MediaDataDecoder::DecodePromise> 
 void ReleaseDataBuffer_s(const uint8_t* buf, void* user_data) {
   MOZ_ASSERT(user_data);
   MOZ_ASSERT(buf);
   DAV1DDecoder* d = static_cast<DAV1DDecoder*>(user_data);
   d->ReleaseDataBuffer(buf);
 }
 
 void DAV1DDecoder::ReleaseDataBuffer(const uint8_t* buf) {
-  // The release callback may be called on a
-  // different thread defined by third party
-  // dav1d execution. Post a task into TaskQueue
-  // to ensure mDecodingBuffers is only ever
-  // accessed on the TaskQueue
+  // The release callback may be called on a different thread defined by the
+  // third party dav1d execution. In that case post a task into TaskQueue to
+  // ensure that mDecodingBuffers is only ever accessed on the TaskQueue.
   RefPtr<DAV1DDecoder> self = this;
-  nsresult rv = mTaskQueue->Dispatch(
-      NS_NewRunnableFunction("DAV1DDecoder::ReleaseDataBuffer", [self, buf]() {
-        DebugOnly<bool> found = self->mDecodingBuffers.Remove(buf);
-        MOZ_ASSERT(found);
-      }));
-  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
-  Unused << rv;
+  auto releaseBuffer = [self, buf] {
+    MOZ_ASSERT(self->mTaskQueue->IsCurrentThreadIn());
+    DebugOnly<bool> found = self->mDecodingBuffers.Remove(buf);
+    MOZ_ASSERT(found);
+  };
+
+  if (mTaskQueue->IsCurrentThreadIn()) {
+    releaseBuffer();
+  } else {
+    nsresult rv = mTaskQueue->Dispatch(NS_NewRunnableFunction(
+        "DAV1DDecoder::ReleaseDataBuffer", std::move(releaseBuffer)));
+    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+    Unused << rv;
+  }
 }
 
 RefPtr<MediaDataDecoder::DecodePromise> DAV1DDecoder::InvokeDecode(
     MediaRawData* aSample) {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   MOZ_ASSERT(aSample);
 
   // Add the buffer to the hashtable in order to increase
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -398,16 +398,17 @@ class gfxPrefs final {
   DECL_GFX_PREF(Live, "dom.vr.display.enumerate.interval",     VRDisplayEnumerateInterval, int32_t, 5000);
   DECL_GFX_PREF(Live, "dom.vr.inactive.timeout",               VRInactiveTimeout, int32_t, 5000);
   DECL_GFX_PREF(Live, "dom.vr.poseprediction.enabled",         VRPosePredictionEnabled, bool, true);
   DECL_GFX_PREF(Live, "dom.vr.require-gesture",                VRRequireGesture, bool, true);
   DECL_GFX_PREF(Live, "dom.vr.puppet.enabled",                 VRPuppetEnabled, bool, false);
   DECL_GFX_PREF(Live, "dom.vr.puppet.submitframe",             VRPuppetSubmitFrame, uint32_t, 0);
   DECL_GFX_PREF(Live, "dom.vr.display.rafMaxDuration",         VRDisplayRafMaxDuration, uint32_t, 50);
   DECL_GFX_PREF(Once, "dom.vr.process.enabled",                VRProcessEnabled, bool, false);
+  DECL_GFX_PREF(Once, "dom.vr.process.startup_timeout_ms",     VRProcessTimeoutMs, int32_t, 5000);
   DECL_GFX_PREF(Once, "dom.vr.service.enabled",                VRServiceEnabled, bool, true);
   DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled",        PointerEventsEnabled, bool, false);
 
   // Make APZ send child-to-screen layer matrices to the chrome process
   // even when the GPU process is in use (behind pref due to IPC errors
   // in reftests) https://bugzilla.mozilla.org/show_bug.cgi?id=1533673
   DECL_GFX_PREF(Live, "fission.apz-matrices-with-gpu-process", FissionApzMatricesWithGpuProcess, bool, false);
 
--- a/gfx/vr/ipc/PVR.ipdl
+++ b/gfx/vr/ipc/PVR.ipdl
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 using mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using mozilla::gfx::OpenVRControllerType from "VRMessageUtils.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 include "VRMessageUtils.h";
 
 include GraphicsMessages;
+include MemoryReportTypes;
 include protocol PVRGPU;
 
 include "VRMessageUtils.h";
 
 namespace mozilla {
 namespace gfx {
 
 async protocol PVR
@@ -22,17 +23,25 @@ parent:
   async NewGPUVRManager(Endpoint<PVRGPUParent> endpoint);
   async Init(GfxPrefSetting[] prefs, GfxVarUpdate[] vars, DevicePrefs devicePrefs);
   async NotifyVsync(TimeStamp vsyncTimestamp);
 
   async UpdatePref(GfxPrefSetting pref);
   async UpdateVar(GfxVarUpdate var);
   async OpenVRControllerActionPathToVR(nsCString aPath);
   async OpenVRControllerManifestPathToVR(OpenVRControllerType aType, nsCString aPath);
-
+  async RequestMemoryReport(uint32_t generation,
+                            bool anonymize,
+                            bool minimizeMemoryUsage,
+                            FileDescriptor? DMDFile);
 child:
+  // Sent when the GPU process has initialized devices. This occurs once, after
+  // Init().
+  async InitComplete();
   async OpenVRControllerActionPathToParent(nsCString aPath);
   async OpenVRControllerManifestPathToParent(OpenVRControllerType aType, nsCString aPath);
   async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
+  async AddMemoryReport(MemoryReport aReport);
+  async FinishMemoryReport(uint32_t aGeneration);
 };
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/vr/ipc/VRChild.cpp
+++ b/gfx/vr/ipc/VRChild.cpp
@@ -7,16 +7,17 @@
 #include "VRChild.h"
 #include "VRProcessParent.h"
 #include "gfxConfig.h"
 
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/VsyncDispatcher.h"
+#include "mozilla/dom/MemoryReportRequest.h"
 #include "mozilla/ipc/CrashReporterHost.h"
 
 namespace mozilla {
 namespace gfx {
 
 class OpenVRControllerManifestManager {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OpenVRControllerManifestManager)
  public:
@@ -61,20 +62,39 @@ class OpenVRControllerManifestManager {
 
   nsCString mAction;
   nsDataHashtable<nsUint32HashKey, nsCString> mManifest;
   DISALLOW_COPY_AND_ASSIGN(OpenVRControllerManifestManager);
 };
 
 StaticRefPtr<OpenVRControllerManifestManager> sOpenVRControllerManifestManager;
 
-VRChild::VRChild(VRProcessParent* aHost) : mHost(aHost) {
+VRChild::VRChild(VRProcessParent* aHost)
+  : mHost(aHost),
+    mVRReady(false) {
   MOZ_ASSERT(XRE_IsParentProcess());
 }
 
+mozilla::ipc::IPCResult VRChild::RecvAddMemoryReport(
+    const MemoryReport& aReport) {
+  if (mMemoryReportRequest) {
+    mMemoryReportRequest->RecvReport(aReport);
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult VRChild::RecvFinishMemoryReport(
+    const uint32_t& aGeneration) {
+  if (mMemoryReportRequest) {
+    mMemoryReportRequest->Finish(aGeneration);
+    mMemoryReportRequest = nullptr;
+  }
+  return IPC_OK();
+}
+
 void VRChild::ActorDestroy(ActorDestroyReason aWhy) {
   if (aWhy == AbnormalShutdown) {
     if (mCrashReporter) {
       mCrashReporter->GenerateCrashReport(OtherPid());
       mCrashReporter = nullptr;
     }
 
     Telemetry::Accumulate(
@@ -139,37 +159,61 @@ void VRChild::Init() {
   if (sOpenVRControllerManifestManager->GetManifestPath(
           OpenVRControllerType::Knuckles, &output)) {
     SendOpenVRControllerManifestPathToVR(OpenVRControllerType::Knuckles,
                                          output);
   }
   gfxVars::AddReceiver(this);
 }
 
+bool VRChild::EnsureVRReady() {
+  if (!mVRReady) {
+    return false;
+  }
+
+  return true;
+}
+
 mozilla::ipc::IPCResult VRChild::RecvOpenVRControllerActionPathToParent(
     const nsCString& aPath) {
   sOpenVRControllerManifestManager->SetOpenVRControllerActionPath(aPath);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult VRChild::RecvOpenVRControllerManifestPathToParent(
     const OpenVRControllerType& aType, const nsCString& aPath) {
   sOpenVRControllerManifestManager->SetOpenVRControllerManifestPath(aType,
                                                                     aPath);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult VRChild::RecvInitComplete() {
+  // We synchronously requested VR parameters before this arrived.
+  mVRReady = true;
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult VRChild::RecvInitCrashReporter(
     Shmem&& aShmem, const NativeThreadId& aThreadId) {
   mCrashReporter = MakeUnique<ipc::CrashReporterHost>(GeckoProcessType_VR,
                                                       aShmem, aThreadId);
 
   return IPC_OK();
 }
 
+bool VRChild::SendRequestMemoryReport(const uint32_t& aGeneration,
+                                       const bool& aAnonymize,
+                                       const bool& aMinimizeMemoryUsage,
+                                       const Maybe<FileDescriptor>& aDMDFile) {
+  mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
+  Unused << PVRChild::SendRequestMemoryReport(aGeneration, aAnonymize,
+                                              aMinimizeMemoryUsage, aDMDFile);
+  return true;
+}
+
 void VRChild::OnVarChanged(const GfxVarUpdate& aVar) { SendUpdateVar(aVar); }
 
 class DeferredDeleteVRChild : public Runnable {
  public:
   explicit DeferredDeleteVRChild(UniquePtr<VRChild>&& aChild)
       : Runnable("gfx::DeferredDeleteVRChild"), mChild(std::move(aChild)) {}
 
   NS_IMETHODIMP Run() override { return NS_OK; }
--- a/gfx/vr/ipc/VRChild.h
+++ b/gfx/vr/ipc/VRChild.h
@@ -11,42 +11,57 @@
 #include "mozilla/gfx/gfxVarReceiver.h"
 #include "mozilla/VsyncDispatcher.h"
 #include "gfxVR.h"
 
 namespace mozilla {
 namespace ipc {
 class CrashReporterHost;
 }  // namespace ipc
+namespace dom {
+class MemoryReportRequestHost;
+}  // namespace dom
 namespace gfx {
 
 class VRProcessParent;
 class VRChild;
 
 class VRChild final : public PVRChild, public gfxVarReceiver {
+  typedef mozilla::dom::MemoryReportRequestHost MemoryReportRequestHost;
   friend class PVRChild;
 
  public:
   explicit VRChild(VRProcessParent* aHost);
   ~VRChild() = default;
 
   static void Destroy(UniquePtr<VRChild>&& aChild);
   void Init();
+  bool EnsureVRReady();
   virtual void OnVarChanged(const GfxVarUpdate& aVar) override;
+  bool SendRequestMemoryReport(const uint32_t& aGeneration,
+                               const bool& aAnonymize,
+                               const bool& aMinimizeMemoryUsage,
+                               const Maybe<ipc::FileDescriptor>& aDMDFile);
 
  protected:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
   mozilla::ipc::IPCResult RecvOpenVRControllerActionPathToParent(
       const nsCString& aPath);
   mozilla::ipc::IPCResult RecvOpenVRControllerManifestPathToParent(
       const OpenVRControllerType& aType, const nsCString& aPath);
+  mozilla::ipc::IPCResult RecvInitComplete();
   mozilla::ipc::IPCResult RecvInitCrashReporter(
       Shmem&& shmem, const NativeThreadId& aThreadId);
 
+  mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport);
+  mozilla::ipc::IPCResult RecvFinishMemoryReport(const uint32_t& aGeneration);
+
  private:
   VRProcessParent* mHost;
   UniquePtr<ipc::CrashReporterHost> mCrashReporter;
+  UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
+  bool mVRReady;
 };
 
 }  // namespace gfx
 }  // namespace mozilla
 
 #endif  // GFX_VR_CHILD_H
--- a/gfx/vr/ipc/VRParent.cpp
+++ b/gfx/vr/ipc/VRParent.cpp
@@ -4,22 +4,24 @@
  * 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 "VRParent.h"
 #include "VRGPUParent.h"
 #include "VRManager.h"
 #include "gfxConfig.h"
 #include "nsDebugImpl.h"
+#include "ProcessUtils.h"
 
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/ipc/CrashReporterClient.h"
 #include "mozilla/ipc/ProcessChild.h"
 
 #if defined(XP_WIN)
+#  include <process.h>
 #  include "mozilla/gfx/DeviceManagerDx.h"
 #endif
 
 namespace mozilla {
 namespace gfx {
 
 using mozilla::ipc::IPCResult;
 
@@ -34,16 +36,18 @@ IPCResult VRParent::RecvNewGPUVRManager(
 
   mVRGPUParent = std::move(vrGPUParent);
   return IPC_OK();
 }
 
 IPCResult VRParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
                              nsTArray<GfxVarUpdate>&& vars,
                              const DevicePrefs& devicePrefs) {
+  Unused << SendInitComplete();
+
   const nsTArray<gfxPrefs::Pref*>& globalPrefs = gfxPrefs::all();
   for (auto& setting : prefs) {
     gfxPrefs::Pref* pref = globalPrefs[setting.index()];
     pref->SetCachedValue(setting.value());
   }
   for (const auto& var : vars) {
     gfxVars::ApplyUpdate(var);
   }
@@ -88,16 +92,33 @@ mozilla::ipc::IPCResult VRParent::RecvOp
 }
 
 mozilla::ipc::IPCResult VRParent::RecvOpenVRControllerManifestPathToVR(
     const OpenVRControllerType& aType, const nsCString& aPath) {
   mOpenVRControllerManifest.Put(static_cast<uint32_t>(aType), aPath);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult VRParent::RecvRequestMemoryReport(
+    const uint32_t& aGeneration, const bool& aAnonymize,
+    const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
+  MOZ_ASSERT(XRE_IsVRProcess());
+  nsPrintfCString processName("VR (pid %u)", (unsigned)getpid());
+
+  mozilla::dom::MemoryReportRequestClient::Start(
+      aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
+      [&](const MemoryReport& aReport) {
+        Unused << SendAddMemoryReport(aReport);
+      },
+      [&](const uint32_t& aGeneration) {
+        return SendFinishMemoryReport(aGeneration);
+      });
+  return IPC_OK();
+}
+
 void VRParent::ActorDestroy(ActorDestroyReason aWhy) {
   if (AbnormalShutdown == aWhy) {
     NS_WARNING("Shutting down VR process early due to a crash!");
     ProcessChild::QuickExit();
   }
   if (mVRGPUParent && !mVRGPUParent->IsClosed()) {
     mVRGPUParent->Close();
   }
@@ -156,16 +177,17 @@ bool VRParent::Init(base::ProcessId aPar
   gfxVars::Initialize();
 #if defined(XP_WIN)
   DeviceManagerDx::Init();
 #endif
   if (NS_FAILED(NS_InitMinimalXPCOM())) {
     return false;
   }
 
+  mozilla::ipc::SetThisProcessName("VR Process");
   return true;
 }
 
 bool VRParent::GetOpenVRControllerActionPath(nsCString* aPath) {
   if (!mOpenVRControllerAction.IsEmpty()) {
     *aPath = mOpenVRControllerAction;
     return true;
   }
--- a/gfx/vr/ipc/VRParent.h
+++ b/gfx/vr/ipc/VRParent.h
@@ -41,16 +41,20 @@ class VRParent final : public PVRParent 
                                    const DevicePrefs& devicePrefs);
   mozilla::ipc::IPCResult RecvNotifyVsync(const TimeStamp& vsyncTimestamp);
   mozilla::ipc::IPCResult RecvUpdatePref(const GfxPrefSetting& setting);
   mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref);
   mozilla::ipc::IPCResult RecvOpenVRControllerActionPathToVR(
       const nsCString& aPath);
   mozilla::ipc::IPCResult RecvOpenVRControllerManifestPathToVR(
       const OpenVRControllerType& aType, const nsCString& aPath);
+  mozilla::ipc::IPCResult RecvRequestMemoryReport(
+      const uint32_t& generation, const bool& anonymize,
+      const bool& minimizeMemoryUsage,
+      const Maybe<ipc::FileDescriptor>& DMDFile);
 
  private:
   nsCString mOpenVRControllerAction;
   nsDataHashtable<nsUint32HashKey, nsCString> mOpenVRControllerManifest;
   RefPtr<VRGPUParent> mVRGPUParent;
   DISALLOW_COPY_AND_ASSIGN(VRParent);
 };
 
--- a/gfx/vr/ipc/VRProcessManager.cpp
+++ b/gfx/vr/ipc/VRProcessManager.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "VRProcessManager.h"
 
 #include "VRProcessParent.h"
 #include "VRChild.h"
 #include "VRGPUChild.h"
 #include "VRGPUParent.h"
+#include "mozilla/MemoryReportingProcess.h"
 
 namespace mozilla {
 namespace gfx {
 
 static StaticAutoPtr<VRProcessManager> sSingleton;
 
 /* static */
 VRProcessManager* VRProcessManager::Get() { return sSingleton; }
@@ -25,17 +26,17 @@ void VRProcessManager::Initialize() {
   if (sSingleton == nullptr) {
     sSingleton = new VRProcessManager();
   }
 }
 
 /* static */
 void VRProcessManager::Shutdown() { sSingleton = nullptr; }
 
-VRProcessManager::VRProcessManager() : mProcess(nullptr) {
+VRProcessManager::VRProcessManager() : mProcess(nullptr), mVRChild(nullptr) {
   MOZ_COUNT_CTOR(VRProcessManager);
 
   mObserver = new Observer(this);
   nsContentUtils::RegisterShutdownObserver(mObserver);
 }
 
 VRProcessManager::~VRProcessManager() {
   MOZ_COUNT_DTOR(VRProcessManager);
@@ -74,24 +75,53 @@ void VRProcessManager::DisableVRProcess(
 
 void VRProcessManager::DestroyProcess() {
   if (!mProcess) {
     return;
   }
 
   mProcess->Shutdown();
   mProcess = nullptr;
+  mVRChild = nullptr;
 
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::VRProcessStatus,
                                      NS_LITERAL_CSTRING("Destroyed"));
 }
 
+bool VRProcessManager::EnsureVRReady() {
+  if (mProcess && !mProcess->IsConnected()) {
+    if (!mProcess->WaitForLaunch()) {
+      // If this fails, we should have fired OnProcessLaunchComplete and
+      // removed the process.
+      MOZ_ASSERT(!mProcess && !mVRChild);
+      return false;
+    }
+  }
+
+  if (mVRChild) {
+    if (mVRChild->EnsureVRReady()) {
+      return true;
+    }
+
+    // If the initialization above fails, we likely have a GPU process teardown
+    // waiting in our message queue (or will soon). We need to ensure we don't
+    // restart it later because if we fail here, our callers assume they should
+    // fall back to a combined UI/GPU process. This also ensures our internal
+    // state is consistent (e.g. process token is reset).
+    DisableVRProcess("Failed to initialize VR process");
+  }
+
+  return false;
+}
+
 void VRProcessManager::OnProcessLaunchComplete(VRProcessParent* aParent) {
   MOZ_ASSERT(mProcess && mProcess == aParent);
 
+  mVRChild = mProcess->GetActor();
+
   if (!mProcess->IsConnected()) {
     DestroyProcess();
     return;
   }
 
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::VRProcessStatus,
                                      NS_LITERAL_CSTRING("Running"));
 }
@@ -161,10 +191,62 @@ void VRProcessManager::OnXPCOMShutdown()
     mObserver = nullptr;
   }
 
   CleanShutdown();
 }
 
 VRChild* VRProcessManager::GetVRChild() { return mProcess->GetActor(); }
 
+class VRMemoryReporter : public MemoryReportingProcess {
+ public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRMemoryReporter, override)
+
+  bool IsAlive() const override {
+    if (VRProcessManager* vpm = VRProcessManager::Get()) {
+      return !!vpm->GetVRChild();
+    }
+    return false;
+  }
+
+  bool SendRequestMemoryReport(const uint32_t& aGeneration,
+                               const bool& aAnonymize,
+                               const bool& aMinimizeMemoryUsage,
+                               const Maybe<FileDescriptor>& aDMDFile) override {
+    VRChild* child = GetChild();
+    if (!child) {
+      return false;
+    }
+
+    return child->SendRequestMemoryReport(aGeneration, aAnonymize,
+                                          aMinimizeMemoryUsage, aDMDFile);
+  }
+
+  int32_t Pid() const override {
+    if (VRChild* child = GetChild()) {
+      return (int32_t)child->OtherPid();
+    }
+    return 0;
+  }
+
+ private:
+  VRChild* GetChild() const {
+    if (VRProcessManager* vpm = VRProcessManager::Get()) {
+      if (VRChild* child = vpm->GetVRChild()) {
+        return child;
+      }
+    }
+    return nullptr;
+  }
+
+ protected:
+  ~VRMemoryReporter() = default;
+};
+
+RefPtr<MemoryReportingProcess> VRProcessManager::GetProcessMemoryReporter() {
+  if (!EnsureVRReady()) {
+    return nullptr;
+  }
+  return new VRMemoryReporter();
+}
+
 }  // namespace gfx
 }  // namespace mozilla
\ No newline at end of file
--- a/gfx/vr/ipc/VRProcessManager.h
+++ b/gfx/vr/ipc/VRProcessManager.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef GFX_VR_PROCESS_MANAGER_H
 #define GFX_VR_PROCESS_MANAGER_H
 
 #include "VRProcessParent.h"
 
 namespace mozilla {
+class MemoryReportingProcess;
 namespace gfx {
 
 class VRManagerChild;
 class PVRGPUChild;
 class VRChild;
 
 // The VRProcessManager is a singleton responsible for creating VR-bound
 // objects that may live in another process.
@@ -22,20 +23,29 @@ class VRProcessManager final : public VR
   static VRProcessManager* Get();
   static void Initialize();
   static void Shutdown();
 
   ~VRProcessManager();
 
   // If not using a VR process, launch a new VR process asynchronously.
   void LaunchVRProcess();
+
+  // Ensure that VR-bound methods can be used. If no VR process is being
+  // used, or one is launched and ready, this function returns immediately.
+  // Otherwise it blocks until the VR process has finished launching.
+  bool EnsureVRReady();
+
   bool CreateGPUBridges(base::ProcessId aOtherProcess,
                         mozilla::ipc::Endpoint<PVRGPUChild>* aOutVRBridge);
 
   VRChild* GetVRChild();
+  // If a VR process is present, create a MemoryReportingProcess object.
+  // Otherwise, return null.
+  RefPtr<MemoryReportingProcess> GetProcessMemoryReporter();
 
   virtual void OnProcessLaunchComplete(VRProcessParent* aParent) override;
   virtual void OnProcessUnexpectedShutdown(VRProcessParent* aParent) override;
 
  private:
   VRProcessManager();
 
   DISALLOW_COPY_AND_ASSIGN(VRProcessManager);
@@ -60,14 +70,15 @@ class VRProcessManager final : public VR
     ~Observer() {}
 
     VRProcessManager* mManager;
   };
   friend class Observer;
 
   RefPtr<Observer> mObserver;
   VRProcessParent* mProcess;
+  VRChild* mVRChild;
 };
 
 }  // namespace gfx
 }  // namespace mozilla
 
 #endif  // GFX_VR_PROCESS_MANAGER_H
--- a/gfx/vr/ipc/VRProcessParent.cpp
+++ b/gfx/vr/ipc/VRProcessParent.cpp
@@ -28,45 +28,74 @@ using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace gfx {
 
 VRProcessParent::VRProcessParent(Listener* aListener)
     : GeckoChildProcessHost(GeckoProcessType_VR),
       mTaskFactory(this),
       mListener(aListener),
+      mLaunchPhase(LaunchPhase::Unlaunched),
       mChannelClosed(false),
       mShutdownRequested(false) {
   MOZ_COUNT_CTOR(VRProcessParent);
 }
 
 VRProcessParent::~VRProcessParent() {
   // Cancel all tasks. We don't want anything triggering after our caller
   // expects this to go away.
   {
     MonitorAutoLock lock(mMonitor);
     mTaskFactory.RevokeAll();
   }
   MOZ_COUNT_DTOR(VRProcessParent);
 }
 
 bool VRProcessParent::Launch() {
+  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
+  MOZ_ASSERT(!mVRChild);
   mLaunchThread = NS_GetCurrentThread();
 
+  mLaunchPhase = LaunchPhase::Waiting;
+
   std::vector<std::string> extraArgs;
   nsCString parentBuildID(mozilla::PlatformBuildID());
   extraArgs.push_back("-parentBuildID");
   extraArgs.push_back(parentBuildID.get());
 
   if (!GeckoChildProcessHost::AsyncLaunch(extraArgs)) {
+    mLaunchPhase = LaunchPhase::Complete;
     return false;
   }
   return true;
 }
 
+bool VRProcessParent::WaitForLaunch() {
+  if (mLaunchPhase == LaunchPhase::Complete) {
+    return !!mVRChild;
+  }
+
+  int32_t timeoutMs = gfxPrefs::VRProcessTimeoutMs();
+
+  // If one of the following environment variables are set we can effectively
+  // ignore the timeout - as we can guarantee the compositor process will be
+  // terminated
+  if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
+      PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
+    timeoutMs = 0;
+  }
+
+  // Our caller expects the connection to be finished after we return, so we
+  // immediately set up the IPDL actor and fire callbacks. The IO thread will
+  // still dispatch a notification to the main thread - we'll just ignore it.
+  bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs);
+  InitAfterConnect(result);
+  return result;
+}
+
 void VRProcessParent::Shutdown() {
   MOZ_ASSERT(!mShutdownRequested);
   mListener = nullptr;
 
   if (mVRChild) {
     // The channel might already be closed if we got here unexpectedly.
     if (!mChannelClosed) {
       mVRChild->Close();
@@ -96,16 +125,20 @@ void VRProcessParent::Shutdown() {
 void VRProcessParent::DestroyProcess() {
   if (mLaunchThread) {
     mLaunchThread->Dispatch(NS_NewRunnableFunction("DestroyProcessRunnable",
                                                    [this] { Destroy(); }));
   }
 }
 
 void VRProcessParent::InitAfterConnect(bool aSucceeded) {
+  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting);
+  MOZ_ASSERT(!mVRChild);
+
+  mLaunchPhase = LaunchPhase::Complete;
   if (aSucceeded) {
     mVRChild = MakeUnique<VRChild>(this);
 
     DebugOnly<bool> rv =
         mVRChild->Open(GetChannel(), base::GetProcId(GetChildProcessHandle()));
     MOZ_ASSERT(rv);
 
     mVRChild->Init();
@@ -152,20 +185,26 @@ void VRProcessParent::OnChannelConnected
   {
     MonitorAutoLock lock(mMonitor);
     runnable = mTaskFactory.NewRunnableMethod(
         &VRProcessParent::OnChannelConnectedTask);
   }
   NS_DispatchToMainThread(runnable);
 }
 
-void VRProcessParent::OnChannelConnectedTask() { InitAfterConnect(true); }
+void VRProcessParent::OnChannelConnectedTask() {
+  if (mLaunchPhase == LaunchPhase::Waiting) {
+    InitAfterConnect(true);
+  }
+}
 
 void VRProcessParent::OnChannelErrorTask() {
-  MOZ_ASSERT(false, "VR process channel error.");
+  if (mLaunchPhase == LaunchPhase::Waiting) {
+    InitAfterConnect(false);
+  }
 }
 
 void VRProcessParent::OnChannelClosed() {
   mChannelClosed = true;
   if (!mShutdownRequested && mListener) {
     // This is an unclean shutdown. Notify we're going away.
     mListener->OnProcessUnexpectedShutdown(this);
   } else {
--- a/gfx/vr/ipc/VRProcessParent.h
+++ b/gfx/vr/ipc/VRProcessParent.h
@@ -27,43 +27,53 @@ class VRProcessParent final : public moz
     // unexpectedly shutdown or had its connection severed.
     // This is not called if an error occurs after calling Shutdown().
     virtual void OnProcessUnexpectedShutdown(VRProcessParent* aParent) {}
   };
 
   explicit VRProcessParent(Listener* aListener);
 
   bool Launch();
+  // If the process is being launched, block until it has launched and
+  // connected. If a launch task is pending, it will fire immediately.
+  //
+  // Returns true if the process is successfully connected; false otherwise.
+  bool WaitForLaunch();
   void Shutdown();
   void DestroyProcess();
   bool CanShutdown() override { return true; }
 
   void OnChannelError() override;
   void OnChannelConnected(int32_t peer_pid) override;
   void OnChannelConnectedTask();
   void OnChannelErrorTask();
   void OnChannelClosed();
   bool IsConnected() const;
 
   base::ProcessId OtherPid();
   VRChild* GetActor() const { return mVRChild.get(); }
+  // Return a unique id for this process, guaranteed not to be shared with any
+  // past or future instance of VRProcessParent.
+  uint64_t GetProcessToken() const;
 
  private:
   ~VRProcessParent();
 
   DISALLOW_COPY_AND_ASSIGN(VRProcessParent);
 
   void InitAfterConnect(bool aSucceeded);
   void KillHard(const char* aReason);
 
   UniquePtr<VRChild> mVRChild;
   mozilla::ipc::TaskFactory<VRProcessParent> mTaskFactory;
   nsCOMPtr<nsIThread> mLaunchThread;
   Listener* mListener;
 
+  enum class LaunchPhase { Unlaunched, Waiting, Complete };
+  LaunchPhase mLaunchPhase;
   bool mChannelClosed;
   bool mShutdownRequested;
 };
 
 }  // namespace gfx
 }  // namespace mozilla
 
 #endif  // ifndef GFX_VR_PROCESS_PARENT_H
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -219,17 +219,17 @@ bool BytecodeEmitter::markSimpleBreakpoi
   }
 
   return true;
 }
 
 bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset) {
   *offset = code().length();
 
-  if (!code().growBy(delta)) {
+  if (!code().growByUninitialized(delta)) {
     ReportOutOfMemory(cx);
     return false;
   }
 
   // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
   // reserve a type set to store its result.
   if (CodeSpec[op].format & JOF_TYPESET) {
     if (typesetCount < JSScript::MaxBytecodeTypeSets) {
@@ -9188,17 +9188,17 @@ bool BytecodeEmitter::emitTree(
       MOZ_ASSERT(0);
   }
 
   return true;
 }
 
 static bool AllocSrcNote(JSContext* cx, SrcNotesVector& notes,
                          unsigned* index) {
-  if (!notes.growBy(1)) {
+  if (!notes.growByUninitialized(1)) {
     ReportOutOfMemory(cx);
     return false;
   }
 
   *index = notes.length() - 1;
   return true;
 }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-11.js
@@ -0,0 +1,28 @@
+// If the async function's promise is already resolved, any attempt to return
+// a differerent return value gets ignored.
+
+let g = newGlobal({newCompartment: true});
+g.eval(`
+    async function f() {
+        throw "ok";
+    }
+`);
+
+let dbg = new Debugger(g);
+
+let hits = 0;
+dbg.onEnterFrame = frame => {
+    frame.onPop = () => {
+        hits += 1;
+
+        // Normal functions can override the return value, but async functions
+        // have already resolved their promise, so this return request will get
+        // ignored.
+        return {return: "FAIL"};
+    };
+};
+
+g.f().catch(x => {
+    assertEq(hits, 1);
+    assertEq(x, "ok");
+});
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-12.js
@@ -0,0 +1,28 @@
+// If the async function's promise is already resolved, any attempt to return
+// a differerent return value gets ignored.
+
+let g = newGlobal({newCompartment: true});
+g.eval(`
+    async function f() {
+        return "ok";
+    }
+`);
+
+let dbg = new Debugger(g);
+
+let hits = 0;
+dbg.onEnterFrame = frame => {
+    frame.onPop = () => {
+        hits += 1;
+
+        // Normal functions can override the return value, but async functions
+        // have already resolved their promise, so this return request will get
+        // ignored.
+        return {return: "FAIL"};
+    };
+};
+
+g.f().then(x => {
+    assertEq(hits, 1);
+    assertEq(x, "ok");
+});
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -437,34 +437,35 @@ struct BaselineStackBuilder {
 #ifdef DEBUG
 static inline bool IsInlinableFallback(ICFallbackStub* icEntry) {
   return icEntry->isCall_Fallback() || icEntry->isGetProp_Fallback() ||
          icEntry->isSetProp_Fallback() || icEntry->isGetElem_Fallback();
 }
 #endif
 
 static inline void* GetStubReturnAddress(JSContext* cx, jsbytecode* pc) {
-  JitRealm* jitRealm = cx->realm()->jitRealm();
+  const BaselineICFallbackCode& code =
+      cx->runtime()->jitRuntime()->baselineICFallbackCode();
 
   if (IsGetPropPC(pc)) {
-    return jitRealm->bailoutReturnAddr(BailoutReturnStub::GetProp);
+    return code.bailoutReturnAddr(BailoutReturnKind::GetProp);
   }
   if (IsSetPropPC(pc)) {
-    return jitRealm->bailoutReturnAddr(BailoutReturnStub::SetProp);
+    return code.bailoutReturnAddr(BailoutReturnKind::SetProp);
   }
   if (IsGetElemPC(pc)) {
-    return jitRealm->bailoutReturnAddr(BailoutReturnStub::GetElem);
+    return code.bailoutReturnAddr(BailoutReturnKind::GetElem);
   }
 
   // This should be a call op of some kind, now.
   MOZ_ASSERT(IsCallPC(pc) && !IsSpreadCallPC(pc));
   if (IsConstructorCallPC(pc)) {
-    return jitRealm->bailoutReturnAddr(BailoutReturnStub::New);
+    return code.bailoutReturnAddr(BailoutReturnKind::New);
   }
-  return jitRealm->bailoutReturnAddr(BailoutReturnStub::Call);
+  return code.bailoutReturnAddr(BailoutReturnKind::Call);
 }
 
 static inline jsbytecode* GetNextNonLoopEntryPc(jsbytecode* pc,
                                                 jsbytecode** skippedLoopEntry) {
   JSOp op = JSOp(*pc);
   if (op == JSOP_GOTO) {
     return pc + GET_JUMP_OFFSET(pc);
   }
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -31,16 +31,17 @@
 #include "jit/SharedICHelpers.h"
 #include "jit/VMFunctions.h"
 #include "js/Conversions.h"
 #include "js/GCVector.h"
 #include "vm/JSFunction.h"
 #include "vm/Opcodes.h"
 #include "vm/SelfHosting.h"
 #include "vm/TypedArrayObject.h"
+#include "vtune/VTuneWrapper.h"
 
 #include "builtin/Boolean-inl.h"
 
 #include "jit/JitFrames-inl.h"
 #include "jit/MacroAssembler-inl.h"
 #include "jit/shared/Lowering-shared-inl.h"
 #include "jit/SharedICHelpers-inl.h"
 #include "jit/VMFunctionList-inl.h"
@@ -49,16 +50,36 @@
 #include "vm/JSScript-inl.h"
 #include "vm/StringObject-inl.h"
 
 using mozilla::DebugOnly;
 
 namespace js {
 namespace jit {
 
+// Class used to emit all Baseline IC fallback code when initializing the
+// JitRuntime.
+class MOZ_RAII FallbackICCodeCompiler final : public ICStubCompilerBase {
+  BaselineICFallbackCode& code;
+  MacroAssembler& masm;
+
+  MOZ_MUST_USE bool emitCall(bool isSpread, bool isConstructing);
+  MOZ_MUST_USE bool emitGetElem(bool hasReceiver);
+  MOZ_MUST_USE bool emitGetProp(bool hasReceiver);
+
+ public:
+  FallbackICCodeCompiler(JSContext* cx, BaselineICFallbackCode& code,
+                         MacroAssembler& masm)
+      : ICStubCompilerBase(cx), code(code), masm(masm) {}
+
+#define DEF_METHOD(kind) MOZ_MUST_USE bool emit_##kind();
+  IC_BASELINE_FALLBACK_CODE_KIND_LIST(DEF_METHOD)
+#undef DEF_METHOD
+};
+
 #ifdef JS_JITSPEW
 void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...) {
   if (JitSpewEnabled(JitSpew_BaselineICFallback)) {
     RootedScript script(cx, GetTopJitJSScript(cx));
     jsbytecode* pc = stub->icEntry()->pc(script);
 
     char fmtbuf[100];
     va_list args;
@@ -103,24 +124,49 @@ ICFallbackStub* ICEntry::fallbackStub() 
 }
 
 void ICEntry::trace(JSTracer* trc) {
   for (ICStub* stub = firstStub(); stub; stub = stub->next()) {
     stub->trace(trc);
   }
 }
 
+// Allocator for Baseline IC fallback stubs. These stubs use trampoline code
+// stored in JitRuntime.
+class MOZ_RAII FallbackStubAllocator {
+  JSContext* cx_;
+  ICStubSpace& stubSpace_;
+  const BaselineICFallbackCode& code_;
+
+ public:
+  FallbackStubAllocator(JSContext* cx, ICStubSpace& stubSpace)
+      : cx_(cx),
+        stubSpace_(stubSpace),
+        code_(cx->runtime()->jitRuntime()->baselineICFallbackCode()) {}
+
+  template <typename T, typename... Args>
+  T* newStub(BaselineICFallbackKind kind, Args&&... args) {
+    TrampolinePtr addr = code_.addr(kind);
+    return ICStub::NewFallback<T>(cx_, &stubSpace_, addr,
+                                  std::forward<Args>(args)...);
+  }
+};
+
 /* static */
 UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
   MOZ_ASSERT(cx->realm()->jitRealm());
   MOZ_ASSERT(jit::IsBaselineEnabled(cx));
 
   FallbackICStubSpace stubSpace;
+  FallbackStubAllocator alloc(cx, stubSpace);
+
   js::Vector<ICEntry, 16, SystemAllocPolicy> icEntries;
 
+  using Kind = BaselineICFallbackKind;
+
   auto addIC = [cx, &icEntries, script](jsbytecode* pc, ICStub* stub) {
     if (!stub) {
       MOZ_ASSERT(cx->isExceptionPending());
       return false;
     }
     uint32_t offset = pc ? script->pcToOffset(pc) : ICEntry::NonOpPCOffset;
     if (!icEntries.emplaceBack(stub, offset)) {
       ReportOutOfMemory(cx);
@@ -128,24 +174,26 @@ UniquePtr<ICScript> ICScript::create(JSC
     }
     return true;
   };
 
   // Add ICEntries and fallback stubs for this/argument type checks.
   // Note: we pass a nullptr pc to indicate this is a non-op IC.
   // See ICEntry::NonOpPCOffset.
   if (JSFunction* fun = script->functionNonDelazifying()) {
-    ICTypeMonitor_Fallback::Compiler compiler(cx, uint32_t(0));
-    if (!addIC(nullptr, compiler.getStub(&stubSpace))) {
+    ICStub* stub =
+        alloc.newStub<ICTypeMonitor_Fallback>(Kind::TypeMonitor, nullptr, 0);
+    if (!addIC(nullptr, stub)) {
       return nullptr;
     }
 
     for (size_t i = 0; i < fun->nargs(); i++) {
-      ICTypeMonitor_Fallback::Compiler compiler(cx, i + 1);
-      if (!addIC(nullptr, compiler.getStub(&stubSpace))) {
+      ICStub* stub = alloc.newStub<ICTypeMonitor_Fallback>(Kind::TypeMonitor,
+                                                           nullptr, i + 1);
+      if (!addIC(nullptr, stub)) {
         return nullptr;
       }
     }
   }
 
   jsbytecode const* pcEnd = script->codeEnd();
 
   // Add ICEntries and fallback stubs for JOF_IC bytecode ops.
@@ -161,250 +209,271 @@ UniquePtr<ICScript> ICScript::create(JSC
     }
 
     switch (op) {
       case JSOP_NOT:
       case JSOP_AND:
       case JSOP_OR:
       case JSOP_IFEQ:
       case JSOP_IFNE: {
-        ICToBool_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICToBool_Fallback>(Kind::ToBool);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_BITNOT:
       case JSOP_NEG:
       case JSOP_INC:
       case JSOP_DEC: {
-        ICUnaryArith_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICUnaryArith_Fallback>(Kind::UnaryArith);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_BITOR:
       case JSOP_BITXOR:
       case JSOP_BITAND:
       case JSOP_LSH:
       case JSOP_RSH:
       case JSOP_URSH:
       case JSOP_ADD:
       case JSOP_SUB:
       case JSOP_MUL:
       case JSOP_DIV:
       case JSOP_MOD:
       case JSOP_POW: {
-        ICBinaryArith_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICBinaryArith_Fallback>(Kind::BinaryArith);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_EQ:
       case JSOP_NE:
       case JSOP_LT:
       case JSOP_LE:
       case JSOP_GT:
       case JSOP_GE:
       case JSOP_STRICTEQ:
       case JSOP_STRICTNE: {
-        ICCompare_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICCompare_Fallback>(Kind::Compare);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_LOOPENTRY: {
-        ICWarmUpCounter_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub =
+            alloc.newStub<ICWarmUpCounter_Fallback>(Kind::WarmUpCounter);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_NEWARRAY: {
         ObjectGroup* group =
             ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
         if (!group) {
           return nullptr;
         }
-        ICNewArray_Fallback::Compiler stubCompiler(cx, group);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub =
+            alloc.newStub<ICNewArray_Fallback>(Kind::NewArray, group);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_NEWOBJECT:
       case JSOP_NEWINIT: {
-        ICNewObject_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICNewObject_Fallback>(Kind::NewObject);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_INITELEM:
       case JSOP_INITHIDDENELEM:
       case JSOP_INITELEM_ARRAY:
       case JSOP_INITELEM_INC:
       case JSOP_SETELEM:
       case JSOP_STRICTSETELEM: {
-        ICSetElem_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICSetElem_Fallback>(Kind::SetElem);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_INITPROP:
       case JSOP_INITLOCKEDPROP:
       case JSOP_INITHIDDENPROP:
       case JSOP_INITGLEXICAL:
       case JSOP_SETPROP:
       case JSOP_STRICTSETPROP:
       case JSOP_SETNAME:
       case JSOP_STRICTSETNAME:
       case JSOP_SETGNAME:
       case JSOP_STRICTSETGNAME: {
-        ICSetProp_Fallback::Compiler compiler(cx);
-        if (!addIC(pc, compiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICSetProp_Fallback>(Kind::SetProp);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_GETPROP:
       case JSOP_CALLPROP:
       case JSOP_LENGTH:
-      case JSOP_GETPROP_SUPER:
       case JSOP_GETBOUNDNAME: {
-        bool hasReceiver = (op == JSOP_GETPROP_SUPER);
-        ICGetProp_Fallback::Compiler compiler(cx, hasReceiver);
-        if (!addIC(pc, compiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICGetProp_Fallback>(Kind::GetProp);
+        if (!addIC(pc, stub)) {
+          return nullptr;
+        }
+        break;
+      }
+      case JSOP_GETPROP_SUPER: {
+        ICStub* stub = alloc.newStub<ICGetProp_Fallback>(Kind::GetPropSuper);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_GETELEM:
-      case JSOP_CALLELEM:
+      case JSOP_CALLELEM: {
+        ICStub* stub = alloc.newStub<ICGetElem_Fallback>(Kind::GetElem);
+        if (!addIC(pc, stub)) {
+          return nullptr;
+        }
+        break;
+      }
       case JSOP_GETELEM_SUPER: {
-        bool hasReceiver = (op == JSOP_GETELEM_SUPER);
-        ICGetElem_Fallback::Compiler stubCompiler(cx, hasReceiver);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICGetElem_Fallback>(Kind::GetElemSuper);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_IN: {
-        ICIn_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICIn_Fallback>(Kind::In);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_HASOWN: {
-        ICHasOwn_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICHasOwn_Fallback>(Kind::HasOwn);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_GETNAME:
       case JSOP_GETGNAME: {
-        ICGetName_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICGetName_Fallback>(Kind::GetName);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_BINDNAME:
       case JSOP_BINDGNAME: {
-        ICBindName_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICBindName_Fallback>(Kind::BindName);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_GETALIASEDVAR:
       case JSOP_GETIMPORT: {
-        ICTypeMonitor_Fallback::Compiler compiler(cx, nullptr);
-        if (!addIC(pc, compiler.getStub(&stubSpace))) {
+        ICStub* stub =
+            alloc.newStub<ICTypeMonitor_Fallback>(Kind::TypeMonitor, nullptr);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_GETINTRINSIC: {
-        ICGetIntrinsic_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub =
+            alloc.newStub<ICGetIntrinsic_Fallback>(Kind::GetIntrinsic);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_CALL:
       case JSOP_CALL_IGNORES_RV:
       case JSOP_CALLITER:
-      case JSOP_SUPERCALL:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
-      case JSOP_NEW:
       case JSOP_EVAL:
       case JSOP_STRICTEVAL: {
-        bool construct = JSOp(*pc) == JSOP_NEW || JSOp(*pc) == JSOP_SUPERCALL;
-        ICCall_Fallback::Compiler stubCompiler(cx,
-                                               /* isConstructing = */ construct,
-                                               /* isSpread = */ false);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICCall_Fallback>(Kind::Call);
+        if (!addIC(pc, stub)) {
+          return nullptr;
+        }
+        break;
+      }
+      case JSOP_SUPERCALL:
+      case JSOP_NEW: {
+        ICStub* stub = alloc.newStub<ICCall_Fallback>(Kind::CallConstructing);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_SPREADCALL:
-      case JSOP_SPREADSUPERCALL:
-      case JSOP_SPREADNEW:
       case JSOP_SPREADEVAL:
       case JSOP_STRICTSPREADEVAL: {
-        bool construct =
-            JSOp(*pc) == JSOP_SPREADNEW || JSOp(*pc) == JSOP_SPREADSUPERCALL;
-        ICCall_Fallback::Compiler stubCompiler(cx,
-                                               /* isConstructing = */ construct,
-                                               /* isSpread = */ true);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICCall_Fallback>(Kind::SpreadCall);
+        if (!addIC(pc, stub)) {
+          return nullptr;
+        }
+        break;
+      }
+      case JSOP_SPREADSUPERCALL:
+      case JSOP_SPREADNEW: {
+        ICStub* stub =
+            alloc.newStub<ICCall_Fallback>(Kind::SpreadCallConstructing);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_INSTANCEOF: {
-        ICInstanceOf_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICInstanceOf_Fallback>(Kind::InstanceOf);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_TYPEOF:
       case JSOP_TYPEOFEXPR: {
-        ICTypeOf_Fallback::Compiler stubCompiler(cx);
-        if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICTypeOf_Fallback>(Kind::TypeOf);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_ITER: {
-        ICGetIterator_Fallback::Compiler compiler(cx);
-        if (!addIC(pc, compiler.getStub(&stubSpace))) {
+        ICStub* stub = alloc.newStub<ICGetIterator_Fallback>(Kind::GetIterator);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       case JSOP_REST: {
         ArrayObject* templateObject = ObjectGroup::newArrayObject(
             cx, nullptr, 0, TenuredObject,
             ObjectGroup::NewArrayKind::UnknownIndex);
         if (!templateObject) {
           return nullptr;
         }
-        ICRest_Fallback::Compiler compiler(cx, templateObject);
-        if (!addIC(pc, compiler.getStub(&stubSpace))) {
+        ICStub* stub =
+            alloc.newStub<ICRest_Fallback>(Kind::Rest, templateObject);
+        if (!addIC(pc, stub)) {
           return nullptr;
         }
         break;
       }
       default:
         MOZ_CRASH("JOF_IC op not handled");
     }
   }
@@ -499,30 +568,29 @@ bool ICStub::makesGCCalls() const {
       return toCacheIR_Monitored()->stubInfo()->makesGCCalls();
     case CacheIR_Updated:
       return toCacheIR_Updated()->stubInfo()->makesGCCalls();
     default:
       return NonCacheIRStubMakesGCCalls(kind());
   }
 }
 
-void ICStub::traceCode(JSTracer* trc, const char* name) {
-  JitCode* stubJitCode = jitCode();
-  TraceManuallyBarrieredEdge(trc, &stubJitCode, name);
-}
-
 void ICStub::updateCode(JitCode* code) {
   // Write barrier on the old code.
   JitCode::writeBarrierPre(jitCode());
   stubCode_ = code->raw();
 }
 
 /* static */
 void ICStub::trace(JSTracer* trc) {
-  traceCode(trc, "shared-stub-jitcode");
+  // Fallback stubs use runtime-wide trampoline code we don't need to trace.
+  if (!usesTrampolineCode()) {
+    JitCode* stubJitCode = jitCode();
+    TraceManuallyBarrieredEdge(trc, &stubJitCode, "baseline-ic-stub-code");
+  }
 
   // If the stub is a monitored fallback stub, then trace the monitor ICs
   // hanging off of that stub.  We don't need to worry about the regular
   // monitored stubs, because the regular monitored stubs will always have a
   // monitored fallback stub that references the same stub chain.
   if (isMonitoredFallback()) {
     ICTypeMonitor_Fallback* lastMonStub =
         toMonitoredFallbackStub()->maybeFallbackMonitorStub();
@@ -776,18 +844,17 @@ bool DoWarmUpCounterFallbackOSR(JSContex
   if (!info) {
     return false;
   }
   *infoPtr = info;
 
   return true;
 }
 
-bool ICWarmUpCounter_Fallback::Compiler::generateStubCode(
-    MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_WarmUpCounter() {
   // Push a stub frame so that we can perform a non-tail call.
   enterStubFrame(masm, R1.scratchReg());
 
   Label noCompiledCode;
   // Call DoWarmUpCounterFallbackOSR to compile/check-for Ion-compiled function
   {
     // Push IonOsrTempData pointer storage
     masm.subFromStackPtr(Imm32(sizeof(void*)));
@@ -1000,22 +1067,24 @@ ICMonitoredStub::ICMonitoredStub(Kind ki
       firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub() ==
           firstMonitorStub_);
 }
 
 bool ICMonitoredFallbackStub::initMonitoringChain(JSContext* cx,
                                                   JSScript* script) {
   MOZ_ASSERT(fallbackMonitorStub_ == nullptr);
 
-  ICTypeMonitor_Fallback::Compiler compiler(cx, this);
   ICStubSpace* space = script->icScript()->fallbackStubSpace();
-  ICTypeMonitor_Fallback* stub = compiler.getStub(space);
+  FallbackStubAllocator alloc(cx, *space);
+  auto* stub = alloc.newStub<ICTypeMonitor_Fallback>(
+      BaselineICFallbackKind::TypeMonitor, this);
   if (!stub) {
     return false;
   }
+
   fallbackMonitorStub_ = stub;
   return true;
 }
 
 bool ICMonitoredFallbackStub::addMonitorStubForValue(JSContext* cx,
                                                      BaselineFrame* frame,
                                                      StackTypeSet* types,
                                                      HandleValue val) {
@@ -1025,18 +1094,19 @@ bool ICMonitoredFallbackStub::addMonitor
     return false;
   }
   return typeMonitorFallback->addMonitorStubForValue(cx, frame, types, val);
 }
 
 bool ICUpdatedStub::initUpdatingChain(JSContext* cx, ICStubSpace* space) {
   MOZ_ASSERT(firstUpdateStub_ == nullptr);
 
-  ICTypeUpdate_Fallback::Compiler compiler(cx);
-  ICTypeUpdate_Fallback* stub = compiler.getStub(space);
+  FallbackStubAllocator alloc(cx, *space);
+  auto* stub =
+      alloc.newStub<ICTypeUpdate_Fallback>(BaselineICFallbackKind::TypeUpdate);
   if (!stub) {
     return false;
   }
 
   firstUpdateStub_ = stub;
   return true;
 }
 
@@ -1044,148 +1114,152 @@ bool ICUpdatedStub::initUpdatingChain(JS
 ICStubSpace* ICStubCompiler::StubSpaceForStub(bool makesGCCalls,
                                               JSScript* script) {
   if (makesGCCalls) {
     return script->icScript()->fallbackStubSpace();
   }
   return script->zone()->jitZone()->optimizedStubSpace();
 }
 
+static void InitMacroAssemblerForICStub(StackMacroAssembler& masm) {
+#ifndef JS_USE_LINK_REGISTER
+  // The first value contains the return addres,
+  // which we pull into ICTailCallReg for tail calls.
+  masm.adjustFrame(sizeof(intptr_t));
+#endif
+#ifdef JS_CODEGEN_ARM
+  masm.setSecondScratchReg(BaselineSecondScratchReg);
+#endif
+}
+
 JitCode* ICStubCompiler::getStubCode() {
   JitRealm* realm = cx->realm()->jitRealm();
 
   // Check for existing cached stubcode.
   uint32_t stubKey = getKey();
   JitCode* stubCode = realm->getStubCode(stubKey);
   if (stubCode) {
     return stubCode;
   }
 
   // Compile new stubcode.
   JitContext jctx(cx, nullptr);
   StackMacroAssembler masm;
-#ifndef JS_USE_LINK_REGISTER
-  // The first value contains the return addres,
-  // which we pull into ICTailCallReg for tail calls.
-  masm.adjustFrame(sizeof(intptr_t));
-#endif
-#ifdef JS_CODEGEN_ARM
-  masm.setSecondScratchReg(BaselineSecondScratchReg);
-#endif
+  InitMacroAssemblerForICStub(masm);
 
   if (!generateStubCode(masm)) {
     return nullptr;
   }
   Linker linker(masm, "getStubCode");
   Rooted<JitCode*> newStubCode(cx, linker.newCode(cx, CodeKind::Baseline));
   if (!newStubCode) {
     return nullptr;
   }
 
   // Cache newly compiled stubcode.
   if (!realm->putStubCode(cx, stubKey, newStubCode)) {
     return nullptr;
   }
 
-  // After generating code, run postGenerateStubCode().  We must not fail
-  // after this point.
-  postGenerateStubCode(masm, newStubCode);
-
   MOZ_ASSERT(entersStubFrame_ == ICStub::NonCacheIRStubMakesGCCalls(kind));
   MOZ_ASSERT(!inStubFrame_);
 
 #ifdef JS_ION_PERF
   writePerfSpewerJitCodeProfile(newStubCode, "BaselineIC");
 #endif
 
   return newStubCode;
 }
 
-bool ICStubCompiler::tailCallVMInternal(MacroAssembler& masm,
-                                        TailCallVMFunctionId id) {
+bool ICStubCompilerBase::tailCallVMInternal(MacroAssembler& masm,
+                                            TailCallVMFunctionId id) {
   TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
   const VMFunctionData& fun = GetVMFunction(id);
   MOZ_ASSERT(fun.expectTailCall == TailCall);
   uint32_t argSize = fun.explicitStackSlots() * sizeof(void*);
   EmitBaselineTailCallVM(code, masm, argSize);
   return true;
 }
 
-bool ICStubCompiler::callVMInternal(MacroAssembler& masm, VMFunctionId id) {
+bool ICStubCompilerBase::callVMInternal(MacroAssembler& masm, VMFunctionId id) {
   MOZ_ASSERT(inStubFrame_);
 
   TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
   MOZ_ASSERT(GetVMFunction(id).expectTailCall == NonTailCall);
 
   EmitBaselineCallVM(code, masm);
   return true;
 }
 
 template <typename Fn, Fn fn>
-bool ICStubCompiler::callVM(MacroAssembler& masm) {
+bool ICStubCompilerBase::callVM(MacroAssembler& masm) {
   VMFunctionId id = VMFunctionToId<Fn, fn>::id;
   return callVMInternal(masm, id);
 }
 
 template <typename Fn, Fn fn>
-bool ICStubCompiler::tailCallVM(MacroAssembler& masm) {
+bool ICStubCompilerBase::tailCallVM(MacroAssembler& masm) {
   TailCallVMFunctionId id = TailCallVMFunctionToId<Fn, fn>::id;
   return tailCallVMInternal(masm, id);
 }
 
-void ICStubCompiler::enterStubFrame(MacroAssembler& masm, Register scratch) {
+void ICStubCompilerBase::enterStubFrame(MacroAssembler& masm,
+                                        Register scratch) {
   EmitBaselineEnterStubFrame(masm, scratch);
 #ifdef DEBUG
   framePushedAtEnterStubFrame_ = masm.framePushed();
 #endif
 
   MOZ_ASSERT(!inStubFrame_);
   inStubFrame_ = true;
 
 #ifdef DEBUG
   entersStubFrame_ = true;
 #endif
 }
 
-void ICStubCompiler::assumeStubFrame() {
+void ICStubCompilerBase::assumeStubFrame() {
   MOZ_ASSERT(!inStubFrame_);
   inStubFrame_ = true;
 
 #ifdef DEBUG
   entersStubFrame_ = true;
 
   // |framePushed| isn't tracked precisely in ICStubs, so simply assume it to
   // be STUB_FRAME_SIZE so that assertions don't fail in leaveStubFrame.
   framePushedAtEnterStubFrame_ = STUB_FRAME_SIZE;
 #endif
 }
 
-void ICStubCompiler::leaveStubFrame(MacroAssembler& masm, bool calledIntoIon) {
+void ICStubCompilerBase::leaveStubFrame(MacroAssembler& masm,
+                                        bool calledIntoIon) {
   MOZ_ASSERT(entersStubFrame_ && inStubFrame_);
   inStubFrame_ = false;
 
 #ifdef DEBUG
   masm.setFramePushed(framePushedAtEnterStubFrame_);
   if (calledIntoIon) {
     masm.adjustFrame(sizeof(intptr_t));  // Calls into ion have this extra.
   }
 #endif
   EmitBaselineLeaveStubFrame(masm, calledIntoIon);
 }
 
-void ICStubCompiler::pushStubPayload(MacroAssembler& masm, Register scratch) {
+void ICStubCompilerBase::pushStubPayload(MacroAssembler& masm,
+                                         Register scratch) {
   if (inStubFrame_) {
     masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
     masm.pushBaselineFramePtr(scratch, scratch);
   } else {
     masm.pushBaselineFramePtr(BaselineFrameReg, scratch);
   }
 }
 
-void ICStubCompiler::PushStubPayload(MacroAssembler& masm, Register scratch) {
+void ICStubCompilerBase::PushStubPayload(MacroAssembler& masm,
+                                         Register scratch) {
   pushStubPayload(masm, scratch);
   masm.adjustFrame(sizeof(intptr_t));
 }
 
 void ICScript::noteAccessedGetter(uint32_t pcOffset) {
   ICEntry& entry = icEntryFromPCOffset(pcOffset);
   ICFallbackStub* stub = entry.fallbackStub();
 
@@ -1422,17 +1496,17 @@ bool DoTypeMonitorFallback(JSContext* cx
   } else {
     types = TypeScript::BytecodeTypes(script, pc);
     TypeScript::Monitor(cx, script, pc, types, value);
   }
 
   return stub->addMonitorStubForValue(cx, frame, types, value);
 }
 
-bool ICTypeMonitor_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_TypeMonitor() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   // Restore the tail call register.
   EmitRestoreTailCallReg(masm);
 
   masm.pushValue(R0);
   masm.push(ICStubReg);
   masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
@@ -1761,17 +1835,17 @@ bool DoTypeUpdateFallback(JSContext* cx,
     // instance we may reallocate dynamic slots before calling this),
     // so ignore OOMs if we failed to attach a stub.
     cx->recoverFromOutOfMemory();
   }
 
   return true;
 }
 
-bool ICTypeUpdate_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_TypeUpdate() {
   // Just store false into R1.scratchReg() and return.
   masm.move32(Imm32(0), R1.scratchReg());
   EmitReturnFromIC(masm);
   return true;
 }
 
 bool ICTypeUpdate_PrimitiveSet::Compiler::generateStubCode(
     MacroAssembler& masm) {
@@ -1887,17 +1961,17 @@ bool DoToBoolFallback(JSContext* cx, Bas
                                    BaselineCacheIRStubKind::Regular, arg);
 
   bool cond = ToBoolean(arg);
   ret.setBoolean(cond);
 
   return true;
 }
 
-bool ICToBool_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_ToBool() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   // Restore the tail call register.
   EmitRestoreTailCallReg(masm);
 
   // Push arguments.
   masm.pushValue(R0);
   masm.push(ICStubReg);
@@ -2101,24 +2175,24 @@ bool DoGetElemSuperFallback(JSContext* c
   if (rhs.isNumber() && rhs.isDouble() &&
       !mozilla::NumberEqualsInt32(rhs.toDouble(), &representable)) {
     stub->setSawNonIntegerIndex();
   }
 
   return true;
 }
 
-bool ICGetElem_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emitGetElem(bool hasReceiver) {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   // Restore the tail call register.
   EmitRestoreTailCallReg(masm);
 
   // Super property getters use a |this| that differs from base object
-  if (hasReceiver_) {
+  if (hasReceiver) {
     // State: receiver in R0, index in R1, obj on the stack
 
     // Ensure stack is fully synced for the expression decompiler.
     // We need: receiver, index, obj
     masm.pushValue(R0);
     masm.pushValue(R1);
     masm.pushValue(Address(masm.getStackPointer(), sizeof(Value) * 2));
 
@@ -2152,17 +2226,23 @@ bool ICGetElem_Fallback::Compiler::gener
       return false;
     }
   }
 
   // This is the resume point used when bailout rewrites call stack to undo
   // Ion inlined frames. The return address pushed onto reconstructed stack
   // will point here.
   assumeStubFrame();
-  bailoutReturnOffset_.bind(masm.currentOffset());
+  if (hasReceiver) {
+    code.initBailoutReturnOffset(BailoutReturnKind::GetElemSuper,
+                                 masm.currentOffset());
+  } else {
+    code.initBailoutReturnOffset(BailoutReturnKind::GetElem,
+                                 masm.currentOffset());
+  }
 
   leaveStubFrame(masm, true);
 
   // When we get here, ICStubReg contains the ICGetElem_Fallback stub,
   // which we can't use to enter the TypeMonitor IC, because it's a
   // MonitoredFallbackStub instead of a MonitoredStub. So, we cheat. Note that
   // we must have a non-null fallbackMonitorStub here because InitFromBailout
   // delazifies.
@@ -2170,22 +2250,22 @@ bool ICGetElem_Fallback::Compiler::gener
                        ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),
                ICStubReg);
   EmitEnterTypeMonitorIC(masm,
                          ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());
 
   return true;
 }
 
-void ICGetElem_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm,
-                                                        Handle<JitCode*> code) {
-  BailoutReturnStub kind = hasReceiver_ ? BailoutReturnStub::GetElemSuper
-                                        : BailoutReturnStub::GetElem;
-  void* address = code->raw() + bailoutReturnOffset_.offset();
-  cx->realm()->jitRealm()->initBailoutReturnAddr(address, getKey(), kind);
+bool FallbackICCodeCompiler::emit_GetElem() {
+  return emitGetElem(/* hasReceiver = */ false);
+}
+
+bool FallbackICCodeCompiler::emit_GetElemSuper() {
+  return emitGetElem(/* hasReceiver = */ true);
 }
 
 static void SetUpdateStubData(ICCacheIR_Updated* stub,
                               const PropertyTypeCheckInfo* info) {
   if (info->isSet()) {
     stub->updateStubGroup() = info->group();
     stub->updateStubId() = info->id();
   }
@@ -2321,17 +2401,17 @@ bool DoSetElemFallback(JSContext* cx, Ba
     if (!attached && !isTemporarilyUnoptimizable) {
       stub->state().trackNotAttached();
     }
   }
 
   return true;
 }
 
-bool ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_SetElem() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   EmitRestoreTailCallReg(masm);
 
   // State: R0: object, R1: index, stack: rhs.
   // For the decompiler, the stack has to be: object, index, rhs,
   // so we push the index, then overwrite the rhs Value with R0
   // and push the rhs value.
@@ -2462,17 +2542,17 @@ bool DoInFallback(JSContext* cx, Baselin
   if (!OperatorIn(cx, key, obj, &cond)) {
     return false;
   }
   res.setBoolean(cond);
 
   return true;
 }
 
-bool ICIn_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_In() {
   EmitRestoreTailCallReg(masm);
 
   // Sync for the decompiler.
   masm.pushValue(R0);
   masm.pushValue(R1);
 
   // Push arguments.
   masm.pushValue(R1);
@@ -2504,17 +2584,17 @@ bool DoHasOwnFallback(JSContext* cx, Bas
   if (!HasOwnProperty(cx, objValue, keyValue, &found)) {
     return false;
   }
 
   res.setBoolean(found);
   return true;
 }
 
-bool ICHasOwn_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_HasOwn() {
   EmitRestoreTailCallReg(masm);
 
   // Sync for the decompiler.
   masm.pushValue(R0);
   masm.pushValue(R1);
 
   // Push arguments.
   masm.pushValue(R1);
@@ -2567,17 +2647,17 @@ bool DoGetNameFallback(JSContext* cx, Ba
   // Add a type monitor stub for the resulting value.
   if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
     return false;
   }
 
   return true;
 }
 
-bool ICGetName_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_GetName() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   EmitRestoreTailCallReg(masm);
 
   masm.push(R0.scratchReg());
   masm.push(ICStubReg);
   pushStubPayload(masm, R0.scratchReg());
 
@@ -2611,17 +2691,17 @@ bool DoBindNameFallback(JSContext* cx, B
   if (!LookupNameUnqualified(cx, name, envChain, &scope)) {
     return false;
   }
 
   res.setObject(*scope);
   return true;
 }
 
-bool ICBindName_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_BindName() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   EmitRestoreTailCallReg(masm);
 
   masm.push(R0.scratchReg());
   masm.push(ICStubReg);
   pushStubPayload(masm, R0.scratchReg());
 
@@ -2657,17 +2737,17 @@ bool DoGetIntrinsicFallback(JSContext* c
   TypeScript::Monitor(cx, script, pc, res);
 
   TryAttachStub<GetIntrinsicIRGenerator>("GetIntrinsic", cx, frame, stub,
                                          BaselineCacheIRStubKind::Regular, res);
 
   return true;
 }
 
-bool ICGetIntrinsic_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_GetIntrinsic() {
   EmitRestoreTailCallReg(masm);
 
   masm.push(ICStubReg);
   pushStubPayload(masm, R0.scratchReg());
 
   using Fn = bool (*)(JSContext*, BaselineFrame*, ICGetIntrinsic_Fallback*,
                       MutableHandleValue);
   return tailCallVM<Fn, DoGetIntrinsicFallback>(masm);
@@ -2832,23 +2912,23 @@ bool DoGetPropSuperFallback(JSContext* c
   // Add a type monitor stub for the resulting value.
   if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
     return false;
   }
 
   return true;
 }
 
-bool ICGetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emitGetProp(bool hasReceiver) {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   EmitRestoreTailCallReg(masm);
 
   // Super property getters use a |this| that differs from base object
-  if (hasReceiver_) {
+  if (hasReceiver) {
     // Push arguments.
     masm.pushValue(R0);
     masm.pushValue(R1);
     masm.push(ICStubReg);
     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
     using Fn = bool (*)(JSContext*, BaselineFrame*, ICGetProp_Fallback*,
                         HandleValue, MutableHandleValue, MutableHandleValue);
@@ -2870,17 +2950,23 @@ bool ICGetProp_Fallback::Compiler::gener
       return false;
     }
   }
 
   // This is the resume point used when bailout rewrites call stack to undo
   // Ion inlined frames. The return address pushed onto reconstructed stack
   // will point here.
   assumeStubFrame();
-  bailoutReturnOffset_.bind(masm.currentOffset());
+  if (hasReceiver) {
+    code.initBailoutReturnOffset(BailoutReturnKind::GetPropSuper,
+                                 masm.currentOffset());
+  } else {
+    code.initBailoutReturnOffset(BailoutReturnKind::GetProp,
+                                 masm.currentOffset());
+  }
 
   leaveStubFrame(masm, true);
 
   // When we get here, ICStubReg contains the ICGetProp_Fallback stub,
   // which we can't use to enter the TypeMonitor IC, because it's a
   // MonitoredFallbackStub instead of a MonitoredStub. So, we cheat. Note that
   // we must have a non-null fallbackMonitorStub here because InitFromBailout
   // delazifies.
@@ -2888,22 +2974,22 @@ bool ICGetProp_Fallback::Compiler::gener
                        ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),
                ICStubReg);
   EmitEnterTypeMonitorIC(masm,
                          ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());
 
   return true;
 }
 
-void ICGetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm,
-                                                        Handle<JitCode*> code) {
-  BailoutReturnStub kind = hasReceiver_ ? BailoutReturnStub::GetPropSuper
-                                        : BailoutReturnStub::GetProp;
-  void* address = code->raw() + bailoutReturnOffset_.offset();
-  cx->realm()->jitRealm()->initBailoutReturnAddr(address, getKey(), kind);
+bool FallbackICCodeCompiler::emit_GetProp() {
+  return emitGetProp(/* hasReceiver = */ false);
+}
+
+bool FallbackICCodeCompiler::emit_GetPropSuper() {
+  return emitGetProp(/* hasReceiver = */ true);
 }
 
 //
 // SetProp_Fallback
 //
 
 bool DoSetPropFallback(JSContext* cx, BaselineFrame* frame,
                        ICSetProp_Fallback* stub, Value* stack, HandleValue lhs,
@@ -3040,17 +3126,17 @@ bool DoSetPropFallback(JSContext* cx, Ba
     if (!attached && !isTemporarilyUnoptimizable) {
       stub->state().trackNotAttached();
     }
   }
 
   return true;
 }
 
-bool ICSetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_SetProp() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   EmitRestoreTailCallReg(masm);
 
   // Ensure stack is fully synced for the expression decompiler.
   // Overwrite the RHS value on top of the stack with the object, then push
   // the RHS in R1 on top of that.
   masm.storeValue(R0, Address(masm.getStackPointer(), 0));
@@ -3074,31 +3160,25 @@ bool ICSetProp_Fallback::Compiler::gener
   if (!tailCallVM<Fn, DoSetPropFallback>(masm)) {
     return false;
   }
 
   // This is the resume point used when bailout rewrites call stack to undo
   // Ion inlined frames. The return address pushed onto reconstructed stack
   // will point here.
   assumeStubFrame();
-  bailoutReturnOffset_.bind(masm.currentOffset());
+  code.initBailoutReturnOffset(BailoutReturnKind::SetProp,
+                               masm.currentOffset());
 
   leaveStubFrame(masm, true);
   EmitReturnFromIC(masm);
 
   return true;
 }
 
-void ICSetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm,
-                                                        Handle<JitCode*> code) {
-  BailoutReturnStub kind = BailoutReturnStub::SetProp;
-  void* address = code->raw() + bailoutReturnOffset_.offset();
-  cx->realm()->jitRealm()->initBailoutReturnAddr(address, getKey(), kind);
-}
-
 //
 // Call_Fallback
 //
 
 static bool TryAttachFunApplyStub(JSContext* cx, ICCall_Fallback* stub,
                                   HandleScript script, jsbytecode* pc,
                                   HandleValue thisv, uint32_t argc, Value* argv,
                                   ICTypeMonitor_Fallback* typeMonitorFallback,
@@ -3881,17 +3961,17 @@ bool DoSpreadCallFallback(JSContext* cx,
   StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
   if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
     return false;
   }
 
   return true;
 }
 
-void ICCallStubCompiler::pushCallArguments(MacroAssembler& masm,
+void ICStubCompilerBase::pushCallArguments(MacroAssembler& masm,
                                            AllocatableGeneralRegisterSet regs,
                                            Register argcReg, bool isJitCall,
                                            bool isConstructing) {
   MOZ_ASSERT(!regs.has(argcReg));
 
   // Account for new.target
   Register count = regs.takeAny();
 
@@ -4190,50 +4270,54 @@ void ICCallStubCompiler::pushArrayArgume
   masm.bind(&copyStart);
   masm.branchPtr(Assembler::Equal, endReg, startReg, &copyDone);
   masm.subPtr(Imm32(sizeof(Value)), endReg);
   masm.pushValue(Address(endReg, 0));
   masm.jump(&copyStart);
   masm.bind(&copyDone);
 }
 
-bool ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emitCall(bool isSpread, bool isConstructing) {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   // Values are on the stack left-to-right. Calling convention wants them
   // right-to-left so duplicate them on the stack in reverse order.
   // |this| and callee are pushed last.
 
   AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
 
-  if (MOZ_UNLIKELY(isSpread_)) {
+  if (MOZ_UNLIKELY(isSpread)) {
     // Push a stub frame so that we can perform a non-tail call.
     enterStubFrame(masm, R1.scratchReg());
 
     // Use BaselineFrameReg instead of BaselineStackReg, because
     // BaselineFrameReg and BaselineStackReg hold the same value just after
     // calling enterStubFrame.
 
     // newTarget
-    if (isConstructing_) {
+    uint32_t valueOffset = 0;
+    if (isConstructing) {
       masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE));
+      valueOffset++;
     }
 
     // array
-    uint32_t valueOffset = isConstructing_;
     masm.pushValue(Address(BaselineFrameReg,
-                           valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
+                           valueOffset * sizeof(Value) + STUB_FRAME_SIZE));
+    valueOffset++;
 
     // this
     masm.pushValue(Address(BaselineFrameReg,
-                           valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
+                           valueOffset * sizeof(Value) + STUB_FRAME_SIZE));
+    valueOffset++;
 
     // callee
     masm.pushValue(Address(BaselineFrameReg,
-                           valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
+                           valueOffset * sizeof(Value) + STUB_FRAME_SIZE));
+    valueOffset++;
 
     masm.push(masm.getStackPointer());
     masm.push(ICStubReg);
 
     PushStubPayload(masm, R0.scratchReg());
 
     using Fn = bool (*)(JSContext*, BaselineFrame*, ICCall_Fallback*, Value*,
                         MutableHandleValue);
@@ -4250,17 +4334,17 @@ bool ICCall_Fallback::Compiler::generate
   }
 
   // Push a stub frame so that we can perform a non-tail call.
   enterStubFrame(masm, R1.scratchReg());
 
   regs.take(R0.scratchReg());  // argc.
 
   pushCallArguments(masm, regs, R0.scratchReg(), /* isJitCall = */ false,
-                    isConstructing_);
+                    isConstructing);
 
   masm.push(masm.getStackPointer());
   masm.push(R0.scratchReg());
   masm.push(ICStubReg);
 
   PushStubPayload(masm, R0.scratchReg());
 
   using Fn = bool (*)(JSContext*, BaselineFrame*, ICCall_Fallback*, uint32_t,
@@ -4271,28 +4355,35 @@ bool ICCall_Fallback::Compiler::generate
 
   leaveStubFrame(masm);
   EmitReturnFromIC(masm);
 
   // This is the resume point used when bailout rewrites call stack to undo
   // Ion inlined frames. The return address pushed onto reconstructed stack
   // will point here.
   assumeStubFrame();
-  bailoutReturnOffset_.bind(masm.currentOffset());
+
+  MOZ_ASSERT(!isSpread);
+
+  if (isConstructing) {
+    code.initBailoutReturnOffset(BailoutReturnKind::New, masm.currentOffset());
+  } else {
+    code.initBailoutReturnOffset(BailoutReturnKind::Call, masm.currentOffset());
+  }
 
   // Load passed-in ThisV into R1 just in case it's needed.  Need to do this
   // before we leave the stub frame since that info will be lost.
   // Current stack:  [...., ThisV, ActualArgc, CalleeToken, Descriptor ]
   masm.loadValue(Address(masm.getStackPointer(), 3 * sizeof(size_t)), R1);
 
   leaveStubFrame(masm, true);
 
   // If this is a |constructing| call, if the callee returns a non-object, we
   // replace it with the |this| object passed in.
-  if (isConstructing_) {
+  if (isConstructing) {
     MOZ_ASSERT(JSReturnOperand == R0);
     Label skipThisReplace;
 
     masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
     masm.moveValue(R1, R0);
 #ifdef DEBUG
     masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
     masm.assumeUnreachable("Failed to return object in constructing call.");
@@ -4310,26 +4401,30 @@ bool ICCall_Fallback::Compiler::generate
                        ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),
                ICStubReg);
   EmitEnterTypeMonitorIC(masm,
                          ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());
 
   return true;
 }
 
-void ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm,
-                                                     Handle<JitCode*> code) {
-  if (MOZ_UNLIKELY(isSpread_)) {
-    return;
-  }
-
-  void* address = code->raw() + bailoutReturnOffset_.offset();
-  BailoutReturnStub kind =
-      isConstructing_ ? BailoutReturnStub::New : BailoutReturnStub::Call;
-  cx->realm()->jitRealm()->initBailoutReturnAddr(address, getKey(), kind);
+bool FallbackICCodeCompiler::emit_Call() {
+  return emitCall(/* isSpread = */ false, /* isConstructing = */ false);
+}
+
+bool FallbackICCodeCompiler::emit_CallConstructing() {
+  return emitCall(/* isSpread = */ false, /* isConstructing = */ true);
+}
+
+bool FallbackICCodeCompiler::emit_SpreadCall() {
+  return emitCall(/* isSpread = */ true, /* isConstructing = */ false);
+}
+
+bool FallbackICCodeCompiler::emit_SpreadCallConstructing() {
+  return emitCall(/* isSpread = */ true, /* isConstructing = */ true);
 }
 
 bool ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm) {
   Label failure;
   AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
   bool canUseTailCallReg = regs.has(ICTailCallReg);
 
   Register argcReg = R0.scratchReg();
@@ -5276,17 +5371,17 @@ bool DoGetIteratorFallback(JSContext* cx
   if (!iterobj) {
     return false;
   }
 
   res.setObject(*iterobj);
   return true;
 }
 
-bool ICGetIterator_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_GetIterator() {
   EmitRestoreTailCallReg(masm);
 
   // Sync stack for the decompiler.
   masm.pushValue(R0);
 
   masm.pushValue(R0);
   masm.push(ICStubReg);
   pushStubPayload(masm, R0.scratchReg());
@@ -5334,17 +5429,17 @@ bool DoInstanceOfFallback(JSContext* cx,
   EnsureTrackPropertyTypes(cx, obj, NameToId(cx->names().prototype));
 
   TryAttachStub<InstanceOfIRGenerator>("InstanceOf", cx, frame, stub,
                                        BaselineCacheIRStubKind::Regular, lhs,
                                        obj);
   return true;
 }
 
-bool ICInstanceOf_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_InstanceOf() {
   EmitRestoreTailCallReg(masm);
 
   // Sync stack for the decompiler.
   masm.pushValue(R0);
   masm.pushValue(R1);
 
   masm.pushValue(R1);
   masm.pushValue(R0);
@@ -5370,17 +5465,17 @@ bool DoTypeOfFallback(JSContext* cx, Bas
                                    BaselineCacheIRStubKind::Regular, val);
 
   JSType type = js::TypeOfValue(val);
   RootedString string(cx, TypeName(type, cx->names()));
   res.setString(string);
   return true;
 }
 
-bool ICTypeOf_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_TypeOf() {
   EmitRestoreTailCallReg(masm);
 
   masm.pushValue(R0);
   masm.push(ICStubReg);
   pushStubPayload(masm, R0.scratchReg());
 
   using Fn = bool (*)(JSContext*, BaselineFrame*, ICTypeOf_Fallback*,
                       HandleValue, MutableHandleValue);
@@ -5459,17 +5554,17 @@ bool DoRestFallback(JSContext* cx, Basel
                                   ObjectGroup::NewArrayKind::UnknownIndex);
   if (!obj) {
     return false;
   }
   res.setObject(*obj);
   return true;
 }
 
-bool ICRest_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_Rest() {
   EmitRestoreTailCallReg(masm);
 
   masm.push(ICStubReg);
   pushStubPayload(masm, R0.scratchReg());
 
   using Fn = bool (*)(JSContext*, BaselineFrame*, ICRest_Fallback*,
                       MutableHandleValue);
   return tailCallVM<Fn, DoRestFallback>(masm);
@@ -5526,17 +5621,17 @@ bool DoUnaryArithFallback(JSContext* cx,
   }
 
   TryAttachStub<UnaryArithIRGenerator>("UniaryArith", cx, frame, stub,
                                        BaselineCacheIRStubKind::Regular, op,
                                        val, res);
   return true;
 }
 
-bool ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_UnaryArith() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   // Restore the tail call register.
   EmitRestoreTailCallReg(masm);
 
   // Ensure stack is fully synced for the expression decompiler.
   masm.pushValue(R0);
 
@@ -5650,17 +5745,17 @@ bool DoBinaryArithFallback(JSContext* cx
   }
 
   TryAttachStub<BinaryArithIRGenerator>("BinaryArith", cx, frame, stub,
                                         BaselineCacheIRStubKind::Regular, op,
                                         lhs, rhs, ret);
   return true;
 }
 
-bool ICBinaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_BinaryArith() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   // Restore the tail call register.
   EmitRestoreTailCallReg(masm);
 
   // Ensure stack is fully synced for the expression decompiler.
   masm.pushValue(R0);
   masm.pushValue(R1);
@@ -5747,17 +5842,17 @@ bool DoCompareFallback(JSContext* cx, Ba
   ret.setBoolean(out);
 
   TryAttachStub<CompareIRGenerator>("Compare", cx, frame, stub,
                                     BaselineCacheIRStubKind::Regular, op, lhs,
                                     rhs);
   return true;
 }
 
-bool ICCompare_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_Compare() {
   MOZ_ASSERT(R0 == JSReturnOperand);
 
   // Restore the tail call register.
   EmitRestoreTailCallReg(masm);
 
   // Ensure stack is fully synced for the expression decompiler.
   masm.pushValue(R0);
   masm.pushValue(R1);
@@ -5808,17 +5903,17 @@ bool DoNewArrayFallback(JSContext* cx, B
       stub->setTemplateObject(templateObject);
     }
   }
 
   res.setObject(*obj);
   return true;
 }
 
-bool ICNewArray_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_NewArray() {
   EmitRestoreTailCallReg(masm);
 
   masm.push(R0.scratchReg());  // length
   masm.push(ICStubReg);        // stub.
   masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
   using Fn = bool (*)(JSContext*, BaselineFrame*, ICNewArray_Fallback*,
                       uint32_t, MutableHandleValue);
@@ -5863,21 +5958,58 @@ bool DoNewObjectFallback(JSContext* cx, 
   if (!obj) {
     return false;
   }
 
   res.setObject(*obj);
   return true;
 }
 
-bool ICNewObject_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
+bool FallbackICCodeCompiler::emit_NewObject() {
   EmitRestoreTailCallReg(masm);
 
   masm.push(ICStubReg);  // stub.
   pushStubPayload(masm, R0.scratchReg());
 
   using Fn = bool (*)(JSContext*, BaselineFrame*, ICNewObject_Fallback*,
                       MutableHandleValue);
   return tailCallVM<Fn, DoNewObjectFallback>(masm);
 }
 
+bool JitRuntime::generateBaselineICFallbackCode(JSContext* cx) {
+  StackMacroAssembler masm;
+
+  BaselineICFallbackCode& fallbackCode = baselineICFallbackCode_.ref();
+  FallbackICCodeCompiler compiler(cx, fallbackCode, masm);
+
+  JitSpew(JitSpew_Codegen, "# Emitting Baseline IC fallback code");
+
+#define EMIT_CODE(kind)                                            \
+  {                                                                \
+    uint32_t offset = startTrampolineCode(masm);                   \
+    InitMacroAssemblerForICStub(masm);                             \
+    if (!compiler.emit_##kind()) {                                 \
+      return false;                                                \
+    }                                                              \
+    fallbackCode.initOffset(BaselineICFallbackKind::kind, offset); \
+  }
+  IC_BASELINE_FALLBACK_CODE_KIND_LIST(EMIT_CODE)
+#undef EMIT_CODE
+
+  Linker linker(masm, "BaselineICFallback");
+  JitCode* code = linker.newCode(cx, CodeKind::Other);
+  if (!code) {
+    return false;
+  }
+
+#ifdef JS_ION_PERF
+  writePerfSpewerJitCodeProfile(code, "BaselineICFallback");
+#endif
+#ifdef MOZ_VTUNE
+  vtune::MarkStub(code, "BaselineICFallback");
+#endif
+
+  fallbackCode.initCode(code);
+  return true;
+}
+
 }  // namespace jit
 }  // namespace js
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -498,33 +498,42 @@ class ICStub {
   enum Trait {
     Regular = 0x0,
     Fallback = 0x1,
     Monitored = 0x2,
     MonitoredFallback = 0x3,
     Updated = 0x4
   };
 
-  void traceCode(JSTracer* trc, const char* name);
   void updateCode(JitCode* stubCode);
   void trace(JSTracer* trc);
 
   template <typename T, typename... Args>
   static T* New(JSContext* cx, ICStubSpace* space, JitCode* code,
                 Args&&... args) {
     if (!code) {
       return nullptr;
     }
     T* result = space->allocate<T>(code, std::forward<Args>(args)...);
     if (!result) {
       ReportOutOfMemory(cx);
     }
     return result;
   }
 
+  template <typename T, typename... Args>
+  static T* NewFallback(JSContext* cx, ICStubSpace* space, TrampolinePtr code,
+                        Args&&... args) {
+    T* result = space->allocate<T>(code, std::forward<Args>(args)...);
+    if (MOZ_UNLIKELY(!result)) {
+      ReportOutOfMemory(cx);
+    }
+    return result;
+  }
+
  protected:
   // The raw jitcode to call for this stub.
   uint8_t* stubCode_;
 
   // Pointer to next IC stub.  This is null for the last IC stub, which should
   // either be a fallback or inert IC stub.
   ICStub* next_;
 
@@ -532,33 +541,41 @@ class ICStub {
   uint16_t extra_;
 
   // The kind of the stub.
   //  High bit is 'isFallback' flag.
   //  Second high bit is 'isMonitored' flag.
   Trait trait_ : 3;
   Kind kind_ : 13;
 
-  inline ICStub(Kind kind, JitCode* stubCode)
-      : stubCode_(stubCode->raw()),
+  inline ICStub(Kind kind, uint8_t* stubCode)
+      : stubCode_(stubCode),
         next_(nullptr),
         extra_(0),
         trait_(Regular),
         kind_(kind) {
     MOZ_ASSERT(stubCode != nullptr);
   }
 
-  inline ICStub(Kind kind, Trait trait, JitCode* stubCode)
-      : stubCode_(stubCode->raw()),
+  inline ICStub(Kind kind, JitCode* stubCode) : ICStub(kind, stubCode->raw()) {
+    MOZ_ASSERT(stubCode != nullptr);
+  }
+
+  inline ICStub(Kind kind, Trait trait, uint8_t* stubCode)
+      : stubCode_(stubCode),
         next_(nullptr),
         extra_(0),
         trait_(trait),
         kind_(kind) {
     MOZ_ASSERT(stubCode != nullptr);
   }
+  inline ICStub(Kind kind, Trait trait, JitCode* stubCode)
+      : ICStub(kind, trait, stubCode->raw()) {
+    MOZ_ASSERT(stubCode != nullptr);
+  }
 
   inline Trait trait() const {
     // Workaround for MSVC reading trait_ as signed value.
     return (Trait)(trait_ & 0x7);
   }
 
  public:
   inline Kind kind() const { return static_cast<Kind>(kind_); }
@@ -635,17 +652,25 @@ class ICStub {
   inline void setNext(ICStub* stub) {
     // Note: next_ only needs to be changed under the compilation lock for
     // non-type-monitor/update ICs.
     next_ = stub;
   }
 
   inline ICStub** addressOfNext() { return &next_; }
 
-  inline JitCode* jitCode() { return JitCode::FromExecutable(stubCode_); }
+  bool usesTrampolineCode() const {
+    // All fallback code is stored in a single JitCode instance, so we can't
+    // call JitCode::FromExecutable on the raw pointer.
+    return isFallback() || isTypeMonitor_Fallback() || isTypeUpdate_Fallback();
+  }
+  JitCode* jitCode() {
+    MOZ_ASSERT(!usesTrampolineCode());
+    return JitCode::FromExecutable(stubCode_);
+  }
 
   inline uint8_t* rawStubCode() const { return stubCode_; }
 
   // This method is not valid on TypeUpdate stub chains!
   inline ICFallbackStub* getChainFallback() {
     ICStub* lastStub = this;
     while (lastStub->next_) {
       lastStub = lastStub->next_;
@@ -700,25 +725,25 @@ class ICFallbackStub : public ICStub {
 
   // A pointer to the location stub pointer that needs to be
   // changed to add a new "last" stub immediately before the fallback
   // stub.  This'll start out pointing to the icEntry's "firstStub_"
   // field, and as new stubs are added, it'll point to the current
   // last stub's "next_" field.
   ICStub** lastStubPtrAddr_;
 
-  ICFallbackStub(Kind kind, JitCode* stubCode)
-      : ICStub(kind, ICStub::Fallback, stubCode),
+  ICFallbackStub(Kind kind, TrampolinePtr stubCode)
+      : ICStub(kind, ICStub::Fallback, stubCode.value),
         icEntry_(nullptr),
         state_(),
         enteredCount_(0),
         lastStubPtrAddr_(nullptr) {}
 
-  ICFallbackStub(Kind kind, Trait trait, JitCode* stubCode)
-      : ICStub(kind, trait, stubCode),
+  ICFallbackStub(Kind kind, Trait trait, TrampolinePtr stubCode)
+      : ICStub(kind, trait, stubCode.value),
         icEntry_(nullptr),
         state_(),
         enteredCount_(0),
         lastStubPtrAddr_(nullptr) {
     MOZ_ASSERT(trait == ICStub::Fallback || trait == ICStub::MonitoredFallback);
   }
 
  public:
@@ -949,51 +974,31 @@ class ICCacheIR_Updated : public ICUpdat
 
   void notePreliminaryObject() { extra_ = 1; }
   bool hasPreliminaryObject() const { return extra_; }
 
   uint8_t* stubDataStart();
 };
 
 // Base class for stubcode compilers.
-class ICStubCompiler {
-  // Prevent GC in the middle of stub compilation.
-  js::gc::AutoSuppressGC suppressGC;
-
+class ICStubCompilerBase {
  protected:
   JSContext* cx;
-  ICStub::Kind kind;
-  bool inStubFrame_;
+  bool inStubFrame_ = false;
 
 #ifdef DEBUG
-  bool entersStubFrame_;
-  uint32_t framePushedAtEnterStubFrame_;
+  bool entersStubFrame_ = false;
+  uint32_t framePushedAtEnterStubFrame_ = 0;
 #endif
 
-  // By default the stubcode key is just the kind.
-  virtual int32_t getKey() const { return static_cast<int32_t>(kind); }
-
-  virtual MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) = 0;
-  virtual void postGenerateStubCode(MacroAssembler& masm,
-                                    Handle<JitCode*> genCode) {}
-
-  JitCode* getStubCode();
-
-  ICStubCompiler(JSContext* cx, ICStub::Kind kind)
-      : suppressGC(cx),
-        cx(cx),
-        kind(kind),
-        inStubFrame_(false)
-#ifdef DEBUG
-        ,
-        entersStubFrame_(false),
-        framePushedAtEnterStubFrame_(0)
-#endif
-  {
-  }
+  explicit ICStubCompilerBase(JSContext* cx) : cx(cx) {}
+
+  void pushCallArguments(MacroAssembler& masm,
+                         AllocatableGeneralRegisterSet regs, Register argcReg,
+                         bool isJitCall, bool isConstructing = false);
 
   // Push a payload specialized per compiler needed to execute stubs.
   void PushStubPayload(MacroAssembler& masm, Register scratch);
   void pushStubPayload(MacroAssembler& masm, Register scratch);
 
   // Emits a tail call to a VMFunction wrapper.
   MOZ_MUST_USE bool tailCallVMInternal(MacroAssembler& masm,
                                        TailCallVMFunctionId id);
@@ -1051,16 +1056,34 @@ class ICStubCompiler {
         regs.take(R1);
         break;
       default:
         MOZ_CRASH("Invalid numInputs");
     }
 
     return regs;
   }
+};
+
+class ICStubCompiler : public ICStubCompilerBase {
+  // Prevent GC in the middle of stub compilation.
+  js::gc::AutoSuppressGC suppressGC;
+
+ protected:
+  ICStub::Kind kind;
+
+  // By default the stubcode key is just the kind.
+  virtual int32_t getKey() const { return static_cast<int32_t>(kind); }
+
+  virtual MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) = 0;
+
+  JitCode* getStubCode();
+
+  ICStubCompiler(JSContext* cx, ICStub::Kind kind)
+      : ICStubCompilerBase(cx), suppressGC(cx), kind(kind) {}
 
  protected:
   template <typename T, typename... Args>
   T* newStub(Args&&... args) {
     return ICStub::New<T>(cx, std::forward<Args>(args)...);
   }
 
  public:
@@ -1075,43 +1098,28 @@ class ICStubCompiler {
 };
 
 // WarmUpCounter_Fallback
 
 // A WarmUpCounter IC chain has only the fallback stub.
 class ICWarmUpCounter_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICWarmUpCounter_Fallback(JitCode* stubCode)
+  explicit ICWarmUpCounter_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::WarmUpCounter_Fallback, stubCode) {}
-
- public:
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::WarmUpCounter_Fallback) {}
-
-    ICWarmUpCounter_Fallback* getStub(ICStubSpace* space) override {
-      return newStub<ICWarmUpCounter_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // Monitored fallback stubs - as the name implies.
 class ICMonitoredFallbackStub : public ICFallbackStub {
  protected:
   // Pointer to the fallback monitor stub. Created lazily by
   // getFallbackMonitorStub if needed.
   ICTypeMonitor_Fallback* fallbackMonitorStub_;
 
-  ICMonitoredFallbackStub(Kind kind, JitCode* stubCode)
+  ICMonitoredFallbackStub(Kind kind, TrampolinePtr stubCode)
       : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
         fallbackMonitorStub_(nullptr) {}
 
  public:
   MOZ_MUST_USE bool initMonitoringChain(JSContext* cx, JSScript* script);
   MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
                                            StackTypeSet* types,
                                            HandleValue val);
@@ -1246,20 +1254,20 @@ class ICTypeMonitor_Fallback : public IC
   bool hasFallbackStub_ : 1;
 
   // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX
   // if this is monitoring the types of values pushed at some bytecode.
   uint32_t argumentIndex_ : 23;
 
   static const uint32_t BYTECODE_INDEX = (1 << 23) - 1;
 
-  ICTypeMonitor_Fallback(JitCode* stubCode,
+  ICTypeMonitor_Fallback(TrampolinePtr stubCode,
                          ICMonitoredFallbackStub* mainFallbackStub,
-                         uint32_t argumentIndex)
-      : ICStub(ICStub::TypeMonitor_Fallback, stubCode),
+                         uint32_t argumentIndex = BYTECODE_INDEX)
+      : ICStub(ICStub::TypeMonitor_Fallback, stubCode.value),
         mainFallbackStub_(mainFallbackStub),
         firstMonitorStub_(thisFromCtor()),
         lastMonitorStubPtrAddr_(nullptr),
         numOptimizedMonitorStubs_(0),
         hasFallbackStub_(mainFallbackStub != nullptr),
         argumentIndex_(argumentIndex) {}
 
   ICTypeMonitor_Fallback* thisFromCtor() { return this; }
@@ -1343,41 +1351,16 @@ class ICTypeMonitor_Fallback : public IC
 
   // Create a new monitor stub for the type of the given value, and
   // add it to this chain.
   MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
                                            StackTypeSet* types,
                                            HandleValue val);
 
   void resetMonitorStubChain(Zone* zone);
-
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-    ICMonitoredFallbackStub* mainFallbackStub_;
-    uint32_t argumentIndex_;
-
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    Compiler(JSContext* cx, ICMonitoredFallbackStub* mainFallbackStub)
-        : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
-          mainFallbackStub_(mainFallbackStub),
-          argumentIndex_(BYTECODE_INDEX) {}
-
-    Compiler(JSContext* cx, uint32_t argumentIndex)
-        : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
-          mainFallbackStub_(nullptr),
-          argumentIndex_(argumentIndex) {}
-
-    ICTypeMonitor_Fallback* getStub(ICStubSpace* space) override {
-      return newStub<ICTypeMonitor_Fallback>(space, getStubCode(),
-                                             mainFallbackStub_, argumentIndex_);
-    }
-  };
 };
 
 class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub {
   friend class ICStubSpace;
 
   ICTypeMonitor_PrimitiveSet(JitCode* stubCode, uint16_t flags)
       : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags) {}
 
@@ -1489,33 +1472,18 @@ class ICTypeMonitor_AnyValue : public IC
 
 // TypeUpdate
 
 // The TypeUpdate fallback is not a regular fallback, since it just
 // forwards to a different entry point in the main fallback stub.
 class ICTypeUpdate_Fallback : public ICStub {
   friend class ICStubSpace;
 
-  explicit ICTypeUpdate_Fallback(JitCode* stubCode)
-      : ICStub(ICStub::TypeUpdate_Fallback, stubCode) {}
-
- public:
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::TypeUpdate_Fallback) {}
-
-    ICTypeUpdate_Fallback* getStub(ICStubSpace* space) override {
-      return newStub<ICTypeUpdate_Fallback>(space, getStubCode());
-    }
-  };
+  explicit ICTypeUpdate_Fallback(TrampolinePtr stubCode)
+      : ICStub(ICStub::TypeUpdate_Fallback, stubCode.value) {}
 };
 
 class ICTypeUpdate_PrimitiveSet : public TypeCheckPrimitiveSetStub {
   friend class ICStubSpace;
 
   ICTypeUpdate_PrimitiveSet(JitCode* stubCode, uint16_t flags)
       : TypeCheckPrimitiveSetStub(TypeUpdate_PrimitiveSet, stubCode, flags) {}
 
@@ -1628,303 +1596,141 @@ class ICTypeUpdate_AnyValue : public ICS
 };
 
 // ToBool
 //      JSOP_IFNE
 
 class ICToBool_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICToBool_Fallback(JitCode* stubCode)
+  explicit ICToBool_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::ToBool_Fallback, stubCode) {}
 
  public:
   static const uint32_t MAX_OPTIMIZED_STUBS = 8;
-
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::ToBool_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICToBool_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // GetElem
 //      JSOP_GETELEM
 //      JSOP_GETELEM_SUPER
 
 class ICGetElem_Fallback : public ICMonitoredFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICGetElem_Fallback(JitCode* stubCode)
+  explicit ICGetElem_Fallback(TrampolinePtr stubCode)
       : ICMonitoredFallbackStub(ICStub::GetElem_Fallback, stubCode) {}
 
   static const uint16_t EXTRA_NEGATIVE_INDEX = 0x1;
   static const uint16_t SAW_NON_INTEGER_INDEX_BIT = 0x2;
 
  public:
   void noteNegativeIndex() { extra_ |= EXTRA_NEGATIVE_INDEX; }
   bool hasNegativeIndex() const { return extra_ & EXTRA_NEGATIVE_INDEX; }
 
   void setSawNonIntegerIndex() { extra_ |= SAW_NON_INTEGER_INDEX_BIT; }
   bool sawNonIntegerIndex() const { return extra_ & SAW_NON_INTEGER_INDEX_BIT; }
-
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    CodeOffset bailoutReturnOffset_;
-    bool hasReceiver_;
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-    void postGenerateStubCode(MacroAssembler& masm,
-                              Handle<JitCode*> code) override;
-
-    virtual int32_t getKey() const override {
-      return static_cast<int32_t>(kind) |
-             (static_cast<int32_t>(hasReceiver_) << 16);
-    }
-
-   public:
-    explicit Compiler(JSContext* cx, bool hasReceiver = false)
-        : ICStubCompiler(cx, ICStub::GetElem_Fallback),
-          hasReceiver_(hasReceiver) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICGetElem_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // SetElem
 //      JSOP_SETELEM
 //      JSOP_INITELEM
 
 class ICSetElem_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICSetElem_Fallback(JitCode* stubCode)
+  explicit ICSetElem_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::SetElem_Fallback, stubCode) {}
 
   static const size_t HasDenseAddFlag = 0x1;
   static const size_t HasTypedArrayOOBFlag = 0x2;
 
  public:
   void noteHasDenseAdd() { extra_ |= HasDenseAddFlag; }
   bool hasDenseAdd() const { return extra_ & HasDenseAddFlag; }
 
   void noteHasTypedArrayOOB() { extra_ |= HasTypedArrayOOBFlag; }
   bool hasTypedArrayOOB() const { return extra_ & HasTypedArrayOOBFlag; }
-
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::SetElem_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICSetElem_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // In
 //      JSOP_IN
 class ICIn_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICIn_Fallback(JitCode* stubCode)
+  explicit ICIn_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::In_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::In_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICIn_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // HasOwn
 //      JSOP_HASOWN
 class ICHasOwn_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICHasOwn_Fallback(JitCode* stubCode)
+  explicit ICHasOwn_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::HasOwn_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::HasOwn_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICHasOwn_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // GetName
 //      JSOP_GETNAME
 //      JSOP_GETGNAME
 class ICGetName_Fallback : public ICMonitoredFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICGetName_Fallback(JitCode* stubCode)
+  explicit ICGetName_Fallback(TrampolinePtr stubCode)
       : ICMonitoredFallbackStub(ICStub::GetName_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::GetName_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICGetName_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // BindName
 //      JSOP_BINDNAME
 class ICBindName_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICBindName_Fallback(JitCode* stubCode)
+  explicit ICBindName_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::BindName_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::BindName_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICBindName_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // GetIntrinsic
 //      JSOP_GETINTRINSIC
 class ICGetIntrinsic_Fallback : public ICMonitoredFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICGetIntrinsic_Fallback(JitCode* stubCode)
+  explicit ICGetIntrinsic_Fallback(TrampolinePtr stubCode)
       : ICMonitoredFallbackStub(ICStub::GetIntrinsic_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::GetIntrinsic_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICGetIntrinsic_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // GetProp
 //     JSOP_GETPROP
 //     JSOP_GETPROP_SUPER
 
 class ICGetProp_Fallback : public ICMonitoredFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICGetProp_Fallback(JitCode* stubCode)
+  explicit ICGetProp_Fallback(TrampolinePtr stubCode)
       : ICMonitoredFallbackStub(ICStub::GetProp_Fallback, stubCode) {}
 
  public:
   static const size_t ACCESSED_GETTER_BIT = 1;
 
   void noteAccessedGetter() { extra_ |= (1u << ACCESSED_GETTER_BIT); }
   bool hasAccessedGetter() const {
     return extra_ & (1u << ACCESSED_GETTER_BIT);
   }
-
-  class Compiler : public ICStubCompiler {
-   protected:
-    CodeOffset bailoutReturnOffset_;
-    bool hasReceiver_;
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-    void postGenerateStubCode(MacroAssembler& masm,
-                              Handle<JitCode*> code) override;
-
-    virtual int32_t getKey() const override {
-      return static_cast<int32_t>(kind) |
-             (static_cast<int32_t>(hasReceiver_) << 16);
-    }
-
-   public:
-    explicit Compiler(JSContext* cx, bool hasReceiver = false)
-        : ICStubCompiler(cx, ICStub::GetProp_Fallback),
-          hasReceiver_(hasReceiver) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICGetProp_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // SetProp
 //     JSOP_SETPROP
 //     JSOP_SETNAME
 //     JSOP_SETGNAME
 //     JSOP_INITPROP
 
 class ICSetProp_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICSetProp_Fallback(JitCode* stubCode)
+  explicit ICSetProp_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::SetProp_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    CodeOffset bailoutReturnOffset_;
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-    void postGenerateStubCode(MacroAssembler& masm,
-                              Handle<JitCode*> code) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::SetProp_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICSetProp_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // Call
 //      JSOP_CALL
 //      JSOP_CALL_IGNORES_RV
 //      JSOP_FUNAPPLY
 //      JSOP_FUNCALL
 //      JSOP_NEW
@@ -1934,19 +1740,16 @@ class ICSetProp_Fallback : public ICFall
 
 class ICCallStubCompiler : public ICStubCompiler {
  protected:
   ICCallStubCompiler(JSContext* cx, ICStub::Kind kind)
       : ICStubCompiler(cx, kind) {}
 
   enum FunApplyThing { FunApply_MagicArgs, FunApply_Array };
 
-  void pushCallArguments(MacroAssembler& masm,
-                         AllocatableGeneralRegisterSet regs, Register argcReg,
-                         bool isJitCall, bool isConstructing = false);
   void pushSpreadCallArguments(MacroAssembler& masm,
                                AllocatableGeneralRegisterSet regs,
                                Register argcReg, bool isJitCall,
                                bool isConstructing);
   void guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure,
                        bool isConstructing);
   Register guardFunApply(MacroAssembler& masm,
                          AllocatableGeneralRegisterSet regs, Register argcReg,
@@ -1959,52 +1762,25 @@ class ICCallStubCompiler : public ICStub
 
 class ICCall_Fallback : public ICMonitoredFallbackStub {
   friend class ICStubSpace;
 
  public:
   static const uint32_t MAX_OPTIMIZED_STUBS = 16;
 
  private:
-  explicit ICCall_Fallback(JitCode* stubCode)
+  explicit ICCall_Fallback(TrampolinePtr stubCode)
       : ICMonitoredFallbackStub(ICStub::Call_Fallback, stubCode) {}
 
  public:
   bool scriptedStubsAreGeneralized() const { return hasStub(Call_AnyScripted); }
   bool nativeStubsAreGeneralized() const {
     // Return hasStub(Call_AnyNative) after Call_AnyNative stub is added.
     return false;
   }
-
-  // Compiler for this stub kind.
-  class Compiler : public ICCallStubCompiler {
-   protected:
-    bool isConstructing_;
-    bool isSpread_;
-    CodeOffset bailoutReturnOffset_;
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-    void postGenerateStubCode(MacroAssembler& masm,
-                              Handle<JitCode*> code) override;
-
-    virtual int32_t getKey() const override {
-      return static_cast<int32_t>(kind) |
-             (static_cast<int32_t>(isSpread_) << 16) |
-             (static_cast<int32_t>(isConstructing_) << 17);
-    }
-
-   public:
-    Compiler(JSContext* cx, bool isConstructing, bool isSpread)
-        : ICCallStubCompiler(cx, ICStub::Call_Fallback),
-          isConstructing_(isConstructing),
-          isSpread_(isSpread) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICCall_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 class ICCall_Scripted : public ICMonitoredStub {
   friend class ICStubSpace;
 
  public:
   // The maximum number of inlineable spread call arguments. Keep this small
   // to avoid controllable stack overflows by attackers passing large arrays
@@ -2416,245 +2192,132 @@ class ICCall_ConstStringSplit : public I
     }
   };
 };
 
 // IC for constructing an iterator from an input value.
 class ICGetIterator_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICGetIterator_Fallback(JitCode* stubCode)
+  explicit ICGetIterator_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::GetIterator_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::GetIterator_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICGetIterator_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // InstanceOf
 //      JSOP_INSTANCEOF
 class ICInstanceOf_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICInstanceOf_Fallback(JitCode* stubCode)
+  explicit ICInstanceOf_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::InstanceOf_Fallback, stubCode) {}
-
- public:
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::InstanceOf_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICInstanceOf_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // TypeOf
 //      JSOP_TYPEOF
 //      JSOP_TYPEOFEXPR
 class ICTypeOf_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICTypeOf_Fallback(JitCode* stubCode)
+  explicit ICTypeOf_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::TypeOf_Fallback, stubCode) {}
 
  public:
   static const uint32_t MAX_OPTIMIZED_STUBS = 6;
-
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::TypeOf_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICTypeOf_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 class ICRest_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
   GCPtrArrayObject templateObject_;
 
-  ICRest_Fallback(JitCode* stubCode, ArrayObject* templateObject)
+  ICRest_Fallback(TrampolinePtr stubCode, ArrayObject* templateObject)
       : ICFallbackStub(ICStub::Rest_Fallback, stubCode),
         templateObject_(templateObject) {}
 
  public:
   static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
   GCPtrArrayObject& templateObject() { return templateObject_; }
-
-  class Compiler : public ICStubCompiler {
-   protected:
-    RootedArrayObject templateObject;
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    Compiler(JSContext* cx, ArrayObject* templateObject)
-        : ICStubCompiler(cx, ICStub::Rest_Fallback),
-          templateObject(cx, templateObject) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICRest_Fallback>(space, getStubCode(), templateObject);
-    }
-  };
 };
 
 // UnaryArith
 //     JSOP_BITNOT
 //     JSOP_NEG
 //     JSOP_INC
 //     JSOP_DEC
 
 class ICUnaryArith_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICUnaryArith_Fallback(JitCode* stubCode)
+  explicit ICUnaryArith_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(UnaryArith_Fallback, stubCode) {
     extra_ = 0;
   }
 
  public:
   bool sawDoubleResult() { return extra_; }
   void setSawDoubleResult() { extra_ = 1; }
-
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::UnaryArith_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICUnaryArith_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // Compare
 //      JSOP_LT
 //      JSOP_LE
 //      JSOP_GT
 //      JSOP_GE
 //      JSOP_EQ
 //      JSOP_NE
 //      JSOP_STRICTEQ
 //      JSOP_STRICTNE
 
 class ICCompare_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICCompare_Fallback(JitCode* stubCode)
+  explicit ICCompare_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::Compare_Fallback, stubCode) {}
-
- public:
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::Compare_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICCompare_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // BinaryArith
 //      JSOP_ADD, JSOP_SUB, JSOP_MUL, JOP_DIV, JSOP_MOD
 //      JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
 //      JSOP_LSH, JSOP_RSH, JSOP_URSH
 
 class ICBinaryArith_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
-  explicit ICBinaryArith_Fallback(JitCode* stubCode)
+  explicit ICBinaryArith_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(BinaryArith_Fallback, stubCode) {
     extra_ = 0;
   }
 
   static const uint16_t SAW_DOUBLE_RESULT_BIT = 0x1;
 
  public:
   static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
   bool sawDoubleResult() const { return extra_ & SAW_DOUBLE_RESULT_BIT; }
   void setSawDoubleResult() { extra_ |= SAW_DOUBLE_RESULT_BIT; }
-
-  // Compiler for this stub kind.
-  class Compiler : public ICStubCompiler {
-   protected:
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICBinaryArith_Fallback>(space, getStubCode());
-    }
-  };
 };
 
 // JSOP_NEWARRAY
 
 class ICNewArray_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
   GCPtrObject templateObject_;
 
   // The group used for objects created here is always available, even if the
   // template object itself is not.
   GCPtrObjectGroup templateGroup_;
 
-  ICNewArray_Fallback(JitCode* stubCode, ObjectGroup* templateGroup)
+  ICNewArray_Fallback(TrampolinePtr stubCode, ObjectGroup* templateGroup)
       : ICFallbackStub(ICStub::NewArray_Fallback, stubCode),
         templateObject_(nullptr),
         templateGroup_(templateGroup) {}
 
  public:
-  class Compiler : public ICStubCompiler {
-    RootedObjectGroup templateGroup;
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    Compiler(JSContext* cx, ObjectGroup* templateGroup)
-        : ICStubCompiler(cx, ICStub::NewArray_Fallback),
-          templateGroup(cx, templateGroup) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICNewArray_Fallback>(space, getStubCode(), templateGroup);
-    }
-  };
-
   GCPtrObject& templateObject() { return templateObject_; }
 
   void setTemplateObject(JSObject* obj) {
     MOZ_ASSERT(obj->group() == templateGroup());
     templateObject_ = obj;
   }
 
   GCPtrObjectGroup& templateGroup() { return templateGroup_; }
@@ -2667,33 +2330,21 @@ class ICNewArray_Fallback : public ICFal
 
 // JSOP_NEWOBJECT
 
 class ICNewObject_Fallback : public ICFallbackStub {
   friend class ICStubSpace;
 
   GCPtrObject templateObject_;
 
-  explicit ICNewObject_Fallback(JitCode* stubCode)
+  explicit ICNewObject_Fallback(TrampolinePtr stubCode)
       : ICFallbackStub(ICStub::NewObject_Fallback, stubCode),
         templateObject_(nullptr) {}
 
  public:
-  class Compiler : public ICStubCompiler {
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-   public:
-    explicit Compiler(JSContext* cx)
-        : ICStubCompiler(cx, ICStub::NewObject_Fallback) {}
-
-    ICStub* getStub(ICStubSpace* space) override {
-      return newStub<ICNewObject_Fallback>(space, getStubCode());
-    }
-  };
-
   GCPtrObject& templateObject() { return templateObject_; }
 
   void setTemplateObject(JSObject* obj) { templateObject_ = obj; }
 };
 
 inline bool IsCacheableDOMProxy(JSObject* obj) {
   if (!obj->is<ProxyObject>()) {
     return false;
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -5,17 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_BaselineICList_h
 #define jit_BaselineICList_h
 
 namespace js {
 namespace jit {
 
-// List of IC stub kinds that can only run in Baseline.
+// List of Baseline IC stub kinds. The stub kind determines the structure of the
+// ICStub data.
 #define IC_BASELINE_STUB_KIND_LIST(_) \
   _(WarmUpCounter_Fallback)           \
                                       \
   _(TypeMonitor_Fallback)             \
   _(TypeMonitor_SingleObject)         \
   _(TypeMonitor_ObjectGroup)          \
   _(TypeMonitor_PrimitiveSet)         \
   _(TypeMonitor_AnyValue)             \
@@ -55,28 +56,62 @@ namespace jit {
                                       \
   _(GetIntrinsic_Fallback)            \
                                       \
   _(SetProp_Fallback)                 \
                                       \
   _(GetIterator_Fallback)             \
                                       \
   _(InstanceOf_Fallback)              \
-  _(InstanceOf_Function)              \
                                       \
   _(TypeOf_Fallback)                  \
                                       \
   _(Rest_Fallback)                    \
                                       \
   _(BinaryArith_Fallback)             \
                                       \
   _(Compare_Fallback)                 \
                                       \
   _(GetProp_Fallback)                 \
                                       \
   _(CacheIR_Regular)                  \
   _(CacheIR_Monitored)                \
   _(CacheIR_Updated)
 
+// List of fallback trampolines. Each of these fallback trampolines exists as
+// part of the JitRuntime. Note that some fallback stubs in previous list may
+// have multiple trampolines in this list. For example, Call_Fallback has
+// constructing/spread variants here with different calling conventions needing
+// different trampolines.
+#define IC_BASELINE_FALLBACK_CODE_KIND_LIST(_) \
+  _(WarmUpCounter)                             \
+  _(TypeMonitor)                               \
+  _(TypeUpdate)                                \
+  _(NewArray)                                  \
+  _(NewObject)                                 \
+  _(ToBool)                                    \
+  _(UnaryArith)                                \
+  _(Call)                                      \
+  _(CallConstructing)                          \
+  _(SpreadCall)                                \
+  _(SpreadCallConstructing)                    \
+  _(GetElem)                                   \
+  _(GetElemSuper)                              \
+  _(SetElem)                                   \
+  _(In)                                        \
+  _(HasOwn)                                    \
+  _(GetName)                                   \
+  _(BindName)                                  \
+  _(GetIntrinsic)                              \
+  _(SetProp)                                   \
+  _(GetIterator)                               \
+  _(InstanceOf)                                \
+  _(TypeOf)                                    \
+  _(Rest)                                      \
+  _(BinaryArith)                               \
+  _(Compare)                                   \
+  _(GetProp)                                   \
+  _(GetPropSuper)
+
 }  // namespace jit
 }  // namespace js
 
 #endif /* jit_BaselineICList_h */
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -195,16 +195,33 @@ uint32_t JitRuntime::startTrampolineCode
 
 bool JitRuntime::initialize(JSContext* cx) {
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
 
   AutoAllocInAtomsZone az(cx);
 
   JitContext jctx(cx, nullptr);
 
+  if (!generateTrampolines(cx)) {
+    return false;
+  }
+
+  if (!generateBaselineICFallbackCode(cx)) {
+    return false;
+  }
+
+  jitcodeGlobalTable_ = cx->new_<JitcodeGlobalTable>();
+  if (!jitcodeGlobalTable_) {
+    return false;
+  }
+
+  return true;
+}
+
+bool JitRuntime::generateTrampolines(JSContext* cx) {
   StackMacroAssembler masm;
 
   Label bailoutTail;
   JitSpew(JitSpew_Codegen, "# Emitting bailout tail stub");
   generateBailoutTailStub(masm, &bailoutTail);
 
   if (cx->runtime()->jitSupportsFloatingPoint) {
     JitSpew(JitSpew_Codegen, "# Emitting bailout tables");
@@ -300,21 +317,16 @@ bool JitRuntime::initialize(JSContext* c
 
 #ifdef JS_ION_PERF
   writePerfSpewerJitCodeProfile(trampolineCode_, "Trampolines");
 #endif
 #ifdef MOZ_VTUNE
   vtune::MarkStub(trampolineCode_, "Trampolines");
 #endif
 
-  jitcodeGlobalTable_ = cx->new_<JitcodeGlobalTable>();
-  if (!jitcodeGlobalTable_) {
-    return false;
-  }
-
   return true;
 }
 
 JitCode* JitRuntime::debugTrapHandler(JSContext* cx) {
   if (!debugTrapHandler_) {
     // JitRuntime code stubs are shared across compartments and have to
     // be allocated in the atoms zone.
     AutoAllocInAtomsZone az(cx);
@@ -556,24 +568,16 @@ void JitRuntime::SweepJitcodeGlobalTable
 }
 
 void JitRealm::sweep(JS::Realm* realm) {
   // Any outstanding compilations should have been cancelled by the GC.
   MOZ_ASSERT(!HasOffThreadIonCompile(realm));
 
   stubCodes_->sweep();
 
-  // If the sweep removed a bailout Fallback stub, nullptr the corresponding
-  // return addr.
-  for (auto& it : bailoutReturnStubInfo_) {
-    if (!stubCodes_->lookup(it.key)) {
-      it = BailoutReturnStubInfo();
-    }
-  }
-
   for (ReadBarrieredJitCode& stub : stubs_) {
     if (stub && IsAboutToBeFinalized(&stub)) {
       stub.set(nullptr);
     }
   }
 }
 
 void JitZone::sweep() { baselineCacheIRStubCodes_.sweep(); }
--- a/js/src/jit/JitRealm.h
+++ b/js/src/jit/JitRealm.h
@@ -4,21 +4,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_JitRealm_h
 #define jit_JitRealm_h
 
 #include "mozilla/Array.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/EnumeratedArray.h"
 #include "mozilla/MemoryReporting.h"
 
 #include <utility>
 
 #include "builtin/TypedObject.h"
+#include "jit/BaselineICList.h"
 #include "jit/CompileInfo.h"
 #include "jit/ICStubSpace.h"
 #include "jit/IonCode.h"
 #include "jit/IonControlFlow.h"
 #include "jit/JitFrames.h"
 #include "jit/shared/Assembler-shared.h"
 #include "js/GCHashTable.h"
 #include "js/Value.h"
@@ -57,16 +59,70 @@ struct EnterJitData {
   unsigned osrNumStackValues;
 
   RootedObject envChain;
   RootedValue result;
 
   bool constructing;
 };
 
+enum class BaselineICFallbackKind {
+#define DEF_ENUM_KIND(kind) kind,
+  IC_BASELINE_FALLBACK_CODE_KIND_LIST(DEF_ENUM_KIND)
+#undef DEF_ENUM_KIND
+      Count
+};
+
+enum class BailoutReturnKind {
+  GetProp,
+  GetPropSuper,
+  SetProp,
+  GetElem,
+  GetElemSuper,
+  Call,
+  New,
+  Count
+};
+
+// Class storing code and offsets for all Baseline IC fallback trampolines. This
+// is stored in JitRuntime and generated when creating the JitRuntime.
+class BaselineICFallbackCode {
+  JitCode* code_ = nullptr;
+  using OffsetArray =
+      mozilla::EnumeratedArray<BaselineICFallbackKind,
+                               BaselineICFallbackKind::Count, uint32_t>;
+  OffsetArray offsets_ = {};
+
+  // Keep track of offset into various baseline stubs' code at return
+  // point from called script.
+  using BailoutReturnArray =
+      mozilla::EnumeratedArray<BailoutReturnKind, BailoutReturnKind::Count,
+                               uint32_t>;
+  BailoutReturnArray bailoutReturnOffsets_ = {};
+
+ public:
+  BaselineICFallbackCode() = default;
+  BaselineICFallbackCode(const BaselineICFallbackCode&) = delete;
+  void operator=(const BaselineICFallbackCode&) = delete;
+
+  void initOffset(BaselineICFallbackKind kind, uint32_t offset) {
+    offsets_[kind] = offset;
+  }
+  void initCode(JitCode* code) { code_ = code; }
+  void initBailoutReturnOffset(BailoutReturnKind kind, uint32_t offset) {
+    bailoutReturnOffsets_[kind] = offset;
+  }
+  TrampolinePtr addr(BaselineICFallbackKind kind) const {
+    return TrampolinePtr(code_->raw() + offsets_[kind]);
+  }
+  uint8_t* bailoutReturnAddr(BailoutReturnKind kind) const {
+    return code_->raw() + bailoutReturnOffsets_[kind];
+  }
+};
+
 typedef void (*EnterJitCode)(void* code, unsigned argc, Value* argv,
                              InterpreterFrame* fp, CalleeToken calleeToken,
                              JSObject* envChain, size_t numStackValues,
                              Value* vp);
 
 class JitcodeGlobalTable;
 
 class JitRuntime {
@@ -150,16 +206,18 @@ class JitRuntime {
   // Maps VMFunctionId to the offset of the wrapper code in trampolineCode_.
   using VMWrapperOffsets = Vector<uint32_t, 0, SystemAllocPolicy>;
   VMWrapperOffsets functionWrapperOffsets_;
 
   // Maps TailCallVMFunctionId to the offset of the wrapper code in
   // trampolineCode_.
   VMWrapperOffsets tailCallFunctionWrapperOffsets_;
 
+  MainThreadData<BaselineICFallbackCode> baselineICFallbackCode_;
+
   // Global table of jitcode native address => bytecode address mappings.
   UnprotectedData<JitcodeGlobalTable*> jitcodeGlobalTable_;
 
 #ifdef DEBUG
   // The number of possible bailing places encounters before forcefully bailing
   // in that place. Zero means inactive.
   MainThreadData<uint32_t> ionBailAfter_;
 #endif
@@ -176,16 +234,19 @@ class JitRuntime {
   using IonBuilderList = mozilla::LinkedList<js::jit::IonBuilder>;
   MainThreadData<IonBuilderList> ionLazyLinkList_;
   MainThreadData<size_t> ionLazyLinkListSize_;
 
   // Counter used to help dismbiguate stubs in CacheIR
   MainThreadData<uint64_t> disambiguationId_;
 
  private:
+  bool generateTrampolines(JSContext* cx);
+  bool generateBaselineICFallbackCode(JSContext* cx);
+
   void generateLazyLinkStub(MacroAssembler& masm);
   void generateInterpreterStub(MacroAssembler& masm);
   void generateDoubleToInt32ValueStub(MacroAssembler& masm);
   void generateProfilerExitFrameTailStub(MacroAssembler& masm,
                                          Label* profilerExitTail);
   void generateExceptionTailStub(MacroAssembler& masm, void* handler,
                                  Label* profilerExitTail);
   void generateBailoutTailStub(MacroAssembler& masm, Label* bailoutTail);
@@ -237,16 +298,20 @@ class JitRuntime {
 
   static void Trace(JSTracer* trc, const js::AutoAccessAtomsZone& access);
   static void TraceJitcodeGlobalTableForMinorGC(JSTracer* trc);
   static MOZ_MUST_USE bool MarkJitcodeGlobalTableIteratively(GCMarker* marker);
   static void SweepJitcodeGlobalTable(JSRuntime* rt);
 
   ExecutableAllocator& execAlloc() { return execAlloc_.ref(); }
 
+  const BaselineICFallbackCode& baselineICFallbackCode() const {
+    return baselineICFallbackCode_.ref();
+  }
+
   IonCompilationId nextCompilationId() {
     return IonCompilationId(nextCompilationId_++);
   }
 
   TrampolinePtr getVMWrapper(const VMFunction& f) const;
 
   TrampolinePtr getVMWrapper(VMFunctionId funId) const {
     MOZ_ASSERT(trampolineCode_);
@@ -466,50 +531,25 @@ class JitZone {
     IonCacheIRStubInfoSet::AddPtr p =
         ionCacheIRStubInfoSet_.lookupForAdd(lookup);
     MOZ_ASSERT(!p);
     return ionCacheIRStubInfoSet_.add(p, std::move(key));
   }
   void purgeIonCacheIRStubInfo() { ionCacheIRStubInfoSet_.clearAndCompact(); }
 };
 
-enum class BailoutReturnStub {
-  GetProp,
-  GetPropSuper,
-  SetProp,
-  GetElem,
-  GetElemSuper,
-  Call,
-  New,
-  Count
-};
-
 class JitRealm {
   friend class JitActivation;
 
   // Map ICStub keys to ICStub shared code objects.
   using ICStubCodeMap =
       GCHashMap<uint32_t, ReadBarrieredJitCode, DefaultHasher<uint32_t>,
                 ZoneAllocPolicy, IcStubCodeMapGCPolicy<uint32_t>>;
   ICStubCodeMap* stubCodes_;
 
-  // Keep track of offset into various baseline stubs' code at return
-  // point from called script.
-  struct BailoutReturnStubInfo {
-    void* addr;
-    uint32_t key;
-
-    BailoutReturnStubInfo() : addr(nullptr), key(0) {}
-    BailoutReturnStubInfo(void* addr_, uint32_t key_)
-        : addr(addr_), key(key_) {}
-  };
-  mozilla::EnumeratedArray<BailoutReturnStub, BailoutReturnStub::Count,
-                           BailoutReturnStubInfo>
-      bailoutReturnStubInfo_;
-
   // The JitRealm stores stubs to concatenate strings inline and perform RegExp
   // calls inline. These bake in zone and realm specific pointers and can't be
   // stored in JitRuntime. They also are dependent on the value of
   // 'stringsCanBeInNursery' and must be flushed when its value changes.
   //
   // These are weak pointers, but they can by accessed during off-thread Ion
   // compilation and therefore can't use the usual read barrier. Instead, we
   // record which stubs have been read and perform the appropriate barriers in
@@ -552,24 +592,16 @@ class JitRealm {
                                 Handle<JitCode*> stubCode) {
     MOZ_ASSERT(stubCode);
     if (!stubCodes_->putNew(key, stubCode.get())) {
       ReportOutOfMemory(cx);
       return false;
     }
     return true;
   }
-  void initBailoutReturnAddr(void* addr, uint32_t key, BailoutReturnStub kind) {
-    MOZ_ASSERT(bailoutReturnStubInfo_[kind].addr == nullptr);
-    bailoutReturnStubInfo_[kind] = BailoutReturnStubInfo{addr, key};
-  }
-  void* bailoutReturnAddr(BailoutReturnStub kind) {
-    MOZ_ASSERT(bailoutReturnStubInfo_[kind].addr);
-    return bailoutReturnStubInfo_[kind].addr;
-  }
 
   JitRealm();
   ~JitRealm();
 
   MOZ_MUST_USE bool initialize(JSContext* cx, bool zoneHasNurseryStrings);
 
   // Initialize code stubs only used by Ion, not Baseline.
   MOZ_MUST_USE bool ensureIonStubsExist(JSContext* cx) {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1640,21 +1640,23 @@ static void AdjustGeneratorResumptionVal
       if (resumeMode == ResumeMode::Throw) {
         return;
       }
 
       Rooted<AsyncFunctionGeneratorObject*> asyncGenObj(
           cx, &genObj->as<AsyncFunctionGeneratorObject>());
 
       // 1.  `return <value>` fulfills and returns the async function's promise.
-      JSObject* promise = AsyncFunctionResolve(
-          cx, asyncGenObj, vp, AsyncFunctionResolveKind::Fulfill);
-      if (!promise) {
-        getAndClearExceptionThenThrow();
-        return;
+      Rooted<PromiseObject*> promise(cx, asyncGenObj->promise());
+      if (promise->state() == JS::PromiseState::Pending) {
+        if (!AsyncFunctionResolve(cx, asyncGenObj, vp,
+                                  AsyncFunctionResolveKind::Fulfill)) {
+          getAndClearExceptionThenThrow();
+          return;
+        }
       }
       vp.setObject(*promise);
 
       // 2.  The generator must be closed.
       asyncGenObj->setClosed();
     } else {
       // We're before entering the actual function code.
 
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -1060,39 +1060,39 @@ WasmToken WasmTokenStream::next() {
           case 'c':
             if (consume(u"ceil")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::F32Ceil, begin,
                                cur_);
             }
             if (consume(u"const")) {
               return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
             }
-            if (consume(u"convert_s/i32")) {
+            if (consume(u"convert_i32_s") || consume(u"convert_s/i32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertSI32,
                                begin, cur_);
             }
-            if (consume(u"convert_u/i32")) {
+            if (consume(u"convert_i32_u") || consume(u"convert_u/i32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertUI32,
                                begin, cur_);
             }
-            if (consume(u"convert_s/i64")) {
+            if (consume(u"convert_i64_s") || consume(u"convert_s/i64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertSI64,
                                begin, cur_);
             }
-            if (consume(u"convert_u/i64")) {
+            if (consume(u"convert_i64_u") || consume(u"convert_u/i64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F32ConvertUI64,
                                begin, cur_);
             }
             if (consume(u"copysign")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::F32CopySign, begin,
                                cur_);
             }
             break;
           case 'd':
-            if (consume(u"demote/f64")) {
+            if (consume(u"demote_f64") || consume(u"demote/f64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F32DemoteF64,
                                begin, cur_);
             }
             if (consume(u"div")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::F32Div, begin,
                                cur_);
             }
             break;
@@ -1154,17 +1154,17 @@ WasmToken WasmTokenStream::next() {
               return WasmToken(WasmToken::UnaryOpcode, Op::F32Neg, begin, cur_);
             }
             if (consume(u"ne")) {
               return WasmToken(WasmToken::ComparisonOpcode, Op::F32Ne, begin,
                                cur_);
             }
             break;
           case 'r':
-            if (consume(u"reinterpret/i32")) {
+            if (consume(u"reinterpret_i32") || consume(u"reinterpret/i32")) {
               return WasmToken(WasmToken::ConversionOpcode,
                                Op::F32ReinterpretI32, begin, cur_);
             }
             break;
           case 's':
             if (consume(u"sqrt")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::F32Sqrt, begin,
                                cur_);
@@ -1204,29 +1204,29 @@ WasmToken WasmTokenStream::next() {
           case 'c':
             if (consume(u"ceil")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::F64Ceil, begin,
                                cur_);
             }
             if (consume(u"const")) {
               return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
             }
-            if (consume(u"convert_s/i32")) {
+            if (consume(u"convert_i32_s") || consume(u"convert_s/i32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertSI32,
                                begin, cur_);
             }
-            if (consume(u"convert_u/i32")) {
+            if (consume(u"convert_i32_u") || consume(u"convert_u/i32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertUI32,
                                begin, cur_);
             }
-            if (consume(u"convert_s/i64")) {
+            if (consume(u"convert_i64_s") || consume(u"convert_s/i64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertSI64,
                                begin, cur_);
             }
-            if (consume(u"convert_u/i64")) {
+            if (consume(u"convert_i64_u") || consume(u"convert_u/i64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F64ConvertUI64,
                                begin, cur_);
             }
             if (consume(u"copysign")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::F64CopySign, begin,
                                cur_);
             }
             break;
@@ -1294,23 +1294,23 @@ WasmToken WasmTokenStream::next() {
               return WasmToken(WasmToken::UnaryOpcode, Op::F64Neg, begin, cur_);
             }
             if (consume(u"ne")) {
               return WasmToken(WasmToken::ComparisonOpcode, Op::F64Ne, begin,
                                cur_);
             }
             break;
           case 'p':
-            if (consume(u"promote/f32")) {
+            if (consume(u"promote_f32") || consume(u"promote/f32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::F64PromoteF32,
                                begin, cur_);
             }
             break;
           case 'r':
-            if (consume(u"reinterpret/i64")) {
+            if (consume(u"reinterpret_i64") || consume(u"reinterpret/i64")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::F64ReinterpretI64,
                                begin, cur_);
             }
             break;
           case 's':
             if (consume(u"sqrt")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::F64Sqrt, begin,
                                cur_);
@@ -1372,45 +1372,45 @@ WasmToken WasmTokenStream::next() {
               return WasmToken(WasmToken::BinaryOpcode, Op::I32Add, begin,
                                cur_);
             }
             if (consume(u"and")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::I32And, begin,
                                cur_);
             }
             if (consume(u"atomic.")) {
-              if (consume(u"rmw8_u.add")) {
+              if (consume(u"rmw8.add_u") || consume(u"rmw8_u.add")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAdd8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.add")) {
+              if (consume(u"rmw16.add_u") || consume(u"rmw16_u.add")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I32AtomicAdd16U, begin, cur_);
               }
               if (consume(u"rmw.add")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAdd,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.and")) {
+              if (consume(u"rmw8.and_u") || consume(u"rmw8_u.and")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAnd8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.and")) {
+              if (consume(u"rmw16.and_u") || consume(u"rmw16_u.and")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I32AtomicAnd16U, begin, cur_);
               }
               if (consume(u"rmw.and")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicAnd,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.cmpxchg")) {
+              if (consume(u"rmw8.cmpxchg_u") || consume(u"rmw8_u.cmpxchg")) {
                 return WasmToken(WasmToken::AtomicCmpXchg,
                                  ThreadOp::I32AtomicCmpXchg8U, begin, cur_);
               }
-              if (consume(u"rmw16_u.cmpxchg")) {
+              if (consume(u"rmw16.cmpxchg_u") || consume(u"rmw16_u.cmpxchg")) {
                 return WasmToken(WasmToken::AtomicCmpXchg,
                                  ThreadOp::I32AtomicCmpXchg16U, begin, cur_);
               }
               if (consume(u"rmw.cmpxchg")) {
                 return WasmToken(WasmToken::AtomicCmpXchg,
                                  ThreadOp::I32AtomicCmpXchg, begin, cur_);
               }
               if (consume(u"load8_u")) {
@@ -1420,21 +1420,21 @@ WasmToken WasmTokenStream::next() {
               if (consume(u"load16_u")) {
                 return WasmToken(WasmToken::AtomicLoad,
                                  ThreadOp::I32AtomicLoad16U, begin, cur_);
               }
               if (consume(u"load")) {
                 return WasmToken(WasmToken::AtomicLoad, ThreadOp::I32AtomicLoad,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.or")) {
+              if (consume(u"rmw8.or_u") || consume(u"rmw8_u.or")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicOr8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.or")) {
+              if (consume(u"rmw16.or_u") || consume(u"rmw16_u.or")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicOr16U,
                                  begin, cur_);
               }
               if (consume(u"rmw.or")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicOr,
                                  begin, cur_);
               }
               if (consume(u"store8_u")) {
@@ -1444,45 +1444,45 @@ WasmToken WasmTokenStream::next() {
               if (consume(u"store16_u")) {
                 return WasmToken(WasmToken::AtomicStore,
                                  ThreadOp::I32AtomicStore16U, begin, cur_);
               }
               if (consume(u"store")) {
                 return WasmToken(WasmToken::AtomicStore,
                                  ThreadOp::I32AtomicStore, begin, cur_);
               }
-              if (consume(u"rmw8_u.sub")) {
+              if (consume(u"rmw8.sub_u") || consume(u"rmw8_u.sub")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicSub8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.sub")) {
+              if (consume(u"rmw16.sub_u") || consume(u"rmw16_u.sub")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I32AtomicSub16U, begin, cur_);
               }
               if (consume(u"rmw.sub")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicSub,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.xor")) {
+              if (consume(u"rmw8.xor_u") || consume(u"rmw8_u.xor")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXor8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.xor")) {
+              if (consume(u"rmw16.xor_u") || consume(u"rmw16_u.xor")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I32AtomicXor16U, begin, cur_);
               }
               if (consume(u"rmw.xor")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXor,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.xchg")) {
+              if (consume(u"rmw8.xchg_u") || consume(u"rmw8_u.xchg")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I32AtomicXchg8U, begin, cur_);
               }
-              if (consume(u"rmw16_u.xchg")) {
+              if (consume(u"rmw16.xchg_u") || consume(u"rmw16_u.xchg")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I32AtomicXchg16U, begin, cur_);
               }
               if (consume(u"rmw.xchg")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I32AtomicXchg,
                                  begin, cur_);
               }
               if (consume(u"wait")) {
@@ -1602,17 +1602,17 @@ WasmToken WasmTokenStream::next() {
             break;
           case 'p':
             if (consume(u"popcnt")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::I32Popcnt, begin,
                                cur_);
             }
             break;
           case 'r':
-            if (consume(u"reinterpret/f32")) {
+            if (consume(u"reinterpret_f32") || consume(u"reinterpret/f32")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::I32ReinterpretF32,
                                begin, cur_);
             }
             if (consume(u"rem_s")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::I32RemS, begin,
                                cur_);
             }
             if (consume(u"rem_u")) {
@@ -1654,51 +1654,51 @@ WasmToken WasmTokenStream::next() {
               }
               if (consume(u"16")) {
                 return WasmToken(WasmToken::Store, Op::I32Store16, begin, cur_);
               }
               break;
             }
             break;
           case 't':
-            if (consume(u"trunc_s/f32")) {
+            if (consume(u"trunc_f32_s") || consume(u"trunc_s/f32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncSF32,
                                begin, cur_);
             }
-            if (consume(u"trunc_s/f64")) {
+            if (consume(u"trunc_f64_s") || consume(u"trunc_s/f64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncSF64,
                                begin, cur_);
             }
-            if (consume(u"trunc_u/f32")) {
+            if (consume(u"trunc_f32_u") || consume(u"trunc_u/f32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncUF32,
                                begin, cur_);
             }
-            if (consume(u"trunc_u/f64")) {
+            if (consume(u"trunc_f64_u") || consume(u"trunc_u/f64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I32TruncUF64,
                                begin, cur_);
             }
-            if (consume(u"trunc_s:sat/f32")) {
+            if (consume(u"trunc_sat_f32_s") || consume(u"trunc_s:sat/f32")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I32TruncSSatF32, begin, cur_);
             }
-            if (consume(u"trunc_s:sat/f64")) {
+            if (consume(u"trunc_sat_f64_s") || consume(u"trunc_s:sat/f64")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I32TruncSSatF64, begin, cur_);
             }
-            if (consume(u"trunc_u:sat/f32")) {
+            if (consume(u"trunc_sat_f32_u") || consume(u"trunc_u:sat/f32")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I32TruncUSatF32, begin, cur_);
             }
-            if (consume(u"trunc_u:sat/f64")) {
+            if (consume(u"trunc_sat_f64_u") || consume(u"trunc_u:sat/f64")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I32TruncUSatF64, begin, cur_);
             }
             break;
           case 'w':
-            if (consume(u"wrap/i64")) {
+            if (consume(u"wrap_i64") || consume(u"wrap/i64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I32WrapI64,
                                begin, cur_);
             }
             break;
           case 'x':
             if (consume(u"xor")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::I32Xor, begin,
                                cur_);
@@ -1718,57 +1718,57 @@ WasmToken WasmTokenStream::next() {
               return WasmToken(WasmToken::BinaryOpcode, Op::I64Add, begin,
                                cur_);
             }
             if (consume(u"and")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::I64And, begin,
                                cur_);
             }
             if (consume(u"atomic.")) {
-              if (consume(u"rmw8_u.add")) {
+              if (consume(u"rmw8.add_u") || consume(u"rmw8_u.add")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAdd8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.add")) {
+              if (consume(u"rmw16.add_u") || consume(u"rmw16_u.add")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicAdd16U, begin, cur_);
               }
-              if (consume(u"rmw32_u.add")) {
+              if (consume(u"rmw32.add_u") || consume(u"rmw32_u.add")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicAdd32U, begin, cur_);
               }
               if (consume(u"rmw.add")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAdd,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.and")) {
+              if (consume(u"rmw8.and_u") || consume(u"rmw8_u.and")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAnd8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.and")) {
+              if (consume(u"rmw16.and_u") || consume(u"rmw16_u.and")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicAnd16U, begin, cur_);
               }
-              if (consume(u"rmw32_u.and")) {
+              if (consume(u"rmw32.and_u") || consume(u"rmw32_u.and")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicAnd32U, begin, cur_);
               }
               if (consume(u"rmw.and")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicAnd,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.cmpxchg")) {
+              if (consume(u"rmw8.cmpxchg_u") || consume(u"rmw8_u.cmpxchg")) {
                 return WasmToken(WasmToken::AtomicCmpXchg,
                                  ThreadOp::I64AtomicCmpXchg8U, begin, cur_);
               }
-              if (consume(u"rmw16_u.cmpxchg")) {
+              if (consume(u"rmw16.cmpxchg_u") || consume(u"rmw16_u.cmpxchg")) {
                 return WasmToken(WasmToken::AtomicCmpXchg,
                                  ThreadOp::I64AtomicCmpXchg16U, begin, cur_);
               }
-              if (consume(u"rmw32_u.cmpxchg")) {
+              if (consume(u"rmw32.cmpxchg_u") || consume(u"rmw32_u.cmpxchg")) {
                 return WasmToken(WasmToken::AtomicCmpXchg,
                                  ThreadOp::I64AtomicCmpXchg32U, begin, cur_);
               }
               if (consume(u"rmw.cmpxchg")) {
                 return WasmToken(WasmToken::AtomicCmpXchg,
                                  ThreadOp::I64AtomicCmpXchg, begin, cur_);
               }
               if (consume(u"load8_u")) {
@@ -1782,25 +1782,25 @@ WasmToken WasmTokenStream::next() {
               if (consume(u"load32_u")) {
                 return WasmToken(WasmToken::AtomicLoad,
                                  ThreadOp::I64AtomicLoad32U, begin, cur_);
               }
               if (consume(u"load")) {
                 return WasmToken(WasmToken::AtomicLoad, ThreadOp::I64AtomicLoad,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.or")) {
+              if (consume(u"rmw8.or_u") || consume(u"rmw8_u.or")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicOr8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.or")) {
+              if (consume(u"rmw16.or_u") || consume(u"rmw16_u.or")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicOr16U,
                                  begin, cur_);
               }
-              if (consume(u"rmw32_u.or")) {
+              if (consume(u"rmw32.or_u") || consume(u"rmw32_u.or")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicOr32U,
                                  begin, cur_);
               }
               if (consume(u"rmw.or")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicOr,
                                  begin, cur_);
               }
               if (consume(u"store8_u")) {
@@ -1814,57 +1814,57 @@ WasmToken WasmTokenStream::next() {
               if (consume(u"store32_u")) {
                 return WasmToken(WasmToken::AtomicStore,
                                  ThreadOp::I64AtomicStore32U, begin, cur_);
               }
               if (consume(u"store")) {
                 return WasmToken(WasmToken::AtomicStore,
                                  ThreadOp::I64AtomicStore, begin, cur_);
               }
-              if (consume(u"rmw8_u.sub")) {
+              if (consume(u"rmw8.sub_u") || consume(u"rmw8_u.sub")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicSub8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.sub")) {
+              if (consume(u"rmw16.sub_u") || consume(u"rmw16_u.sub")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicSub16U, begin, cur_);
               }
-              if (consume(u"rmw32_u.sub")) {
+              if (consume(u"rmw32.sub_u") || consume(u"rmw32_u.sub")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicSub32U, begin, cur_);
               }
               if (consume(u"rmw.sub")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicSub,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.xor")) {
+              if (consume(u"rmw8.xor_u") || consume(u"rmw8_u.xor")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXor8U,
                                  begin, cur_);
               }
-              if (consume(u"rmw16_u.xor")) {
+              if (consume(u"rmw16.xor_u") || consume(u"rmw16_u.xor")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicXor16U, begin, cur_);
               }
-              if (consume(u"rmw32_u.xor")) {
+              if (consume(u"rmw32.xor_u") || consume(u"rmw32_u.xor")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicXor32U, begin, cur_);
               }
               if (consume(u"rmw.xor")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXor,
                                  begin, cur_);
               }
-              if (consume(u"rmw8_u.xchg")) {
+              if (consume(u"rmw8.xchg_u") || consume(u"rmw8_u.xchg")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicXchg8U, begin, cur_);
               }
-              if (consume(u"rmw16_u.xchg")) {
+              if (consume(u"rmw16.xchg_u") || consume(u"rmw16_u.xchg")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicXchg16U, begin, cur_);
               }
-              if (consume(u"rmw32_u.xchg")) {
+              if (consume(u"rmw32.xchg_u") || consume(u"rmw32_u.xchg")) {
                 return WasmToken(WasmToken::AtomicRMW,
                                  ThreadOp::I64AtomicXchg32U, begin, cur_);
               }
               if (consume(u"rmw.xchg")) {
                 return WasmToken(WasmToken::AtomicRMW, ThreadOp::I64AtomicXchg,
                                  begin, cur_);
               }
               if (consume(u"wait")) {
@@ -1897,21 +1897,21 @@ WasmToken WasmTokenStream::next() {
           case 'e':
             if (consume(u"eqz")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::I64Eqz, begin, cur_);
             }
             if (consume(u"eq")) {
               return WasmToken(WasmToken::ComparisonOpcode, Op::I64Eq, begin,
                                cur_);
             }
-            if (consume(u"extend_s/i32")) {
+            if (consume(u"extend_i32_s") || consume(u"extend_s/i32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I64ExtendSI32,
                                begin, cur_);
             }
-            if (consume(u"extend_u/i32")) {
+            if (consume(u"extend_i32_u") || consume(u"extend_u/i32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I64ExtendUI32,
                                begin, cur_);
             }
             if (consume(u"extend8_s")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I64Extend8S,
                                begin, cur_);
             }
             if (consume(u"extend16_s")) {
@@ -2002,17 +2002,17 @@ WasmToken WasmTokenStream::next() {
             break;
           case 'p':
             if (consume(u"popcnt")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::I64Popcnt, begin,
                                cur_);
             }
             break;
           case 'r':
-            if (consume(u"reinterpret/f64")) {
+            if (consume(u"reinterpret_f64") || consume(u"reinterpret/f64")) {
               return WasmToken(WasmToken::UnaryOpcode, Op::I64ReinterpretF64,
                                begin, cur_);
             }
             if (consume(u"rem_s")) {
               return WasmToken(WasmToken::BinaryOpcode, Op::I64RemS, begin,
                                cur_);
             }
             if (consume(u"rem_u")) {
@@ -2057,45 +2057,45 @@ WasmToken WasmTokenStream::next() {
               }
               if (consume(u"32")) {
                 return WasmToken(WasmToken::Store, Op::I64Store32, begin, cur_);
               }
               break;
             }
             break;
           case 't':
-            if (consume(u"trunc_s/f32")) {
+            if (consume(u"trunc_f32_s") || consume(u"trunc_s/f32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncSF32,
                                begin, cur_);
             }
-            if (consume(u"trunc_s/f64")) {
+            if (consume(u"trunc_f64_s") || consume(u"trunc_s/f64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncSF64,
                                begin, cur_);
             }
-            if (consume(u"trunc_u/f32")) {
+            if (consume(u"trunc_f32_u") || consume(u"trunc_u/f32")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncUF32,
                                begin, cur_);
             }
-            if (consume(u"trunc_u/f64")) {
+            if (consume(u"trunc_f64_u") || consume(u"trunc_u/f64")) {
               return WasmToken(WasmToken::ConversionOpcode, Op::I64TruncUF64,
                                begin, cur_);
             }
-            if (consume(u"trunc_s:sat/f32")) {
+            if (consume(u"trunc_sat_f32_s") || consume(u"trunc_s:sat/f32")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I64TruncSSatF32, begin, cur_);
             }
-            if (consume(u"trunc_s:sat/f64")) {
+            if (consume(u"trunc_sat_f64_s") || consume(u"trunc_s:sat/f64")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I64TruncSSatF64, begin, cur_);
             }
-            if (consume(u"trunc_u:sat/f32")) {
+            if (consume(u"trunc_sat_f32_u") || consume(u"trunc_u:sat/f32")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I64TruncUSatF32, begin, cur_);
             }
-            if (consume(u"trunc_u:sat/f64")) {
+            if (consume(u"trunc_sat_f64_u") || consume(u"trunc_u:sat/f64")) {
               return WasmToken(WasmToken::ExtraConversionOpcode,
                                MiscOp::I64TruncUSatF64, begin, cur_);
             }
             break;
           case 'w':
             break;
           case 'x':
             if (consume(u"xor")) {
@@ -2120,16 +2120,19 @@ WasmToken WasmTokenStream::next() {
     case 'l':
       if (consume(u"local")) {
         if (consume(u".get")) {
           return WasmToken(WasmToken::GetLocal, begin, cur_);
         }
         if (consume(u".set")) {
           return WasmToken(WasmToken::SetLocal, begin, cur_);
         }
+        if (consume(u".tee")) {
+          return WasmToken(WasmToken::TeeLocal, begin, cur_);
+        }
         return WasmToken(WasmToken::Local, begin, cur_);
       }
       if (consume(u"loop")) {
         return WasmToken(WasmToken::Loop, begin, cur_);
       }
       break;
 
     case 'm':
--- a/layout/style/test/test_font_loading_api.html
+++ b/layout/style/test/test_font_loading_api.html
@@ -404,16 +404,23 @@ function runTest() {
     });
     return p;
 
   }).then(function() {
 
     // (TEST 18) Test passing valid url() source strings to the FontFace
     // constructor.
     var p = Promise.resolve();
+
+    // The sub-test is very fragile on Android platform, see Bug 1455824,
+    // especially Comment 34.
+    if (navigator.appVersion.includes("Android")) {
+      return p;
+    }
+
     sourceWindows.forEach(function({ win, what }) {
       p = p.then(function() {
         var srcTests = Promise.resolve();
         gCSSFontFaceDescriptors.src.values.forEach(function(aSrc) {
           srcTests = srcTests.then(function() {
             var face = new win.FontFace("test", aSrc);
             return face.load().then(function() {
               ok(true, "FontFace should load with valid url() src " + aSrc + " (TEST 18) (" + what + ")");
--- a/layout/svg/crashtests/951904-1.html
+++ b/layout/svg/crashtests/951904-1.html
@@ -16,19 +16,28 @@
           <text>Mercredi</text>
         </mask>
       </g>
       <text id="e">Goodbye</text>
       <a><text id="f">Goodbye</text></a>
     </switch>
   </switch>
 </svg>
+<svg>
+  <switch>
+    <mask>
+      <text id="g">Vendredi</text>
+    </mask>
+    <a></a>
+  </switch>
+</svg>
 </body>
 <script>
 function go() {
   a.getComputedTextLength();
   b.getComputedTextLength();
   c.getComputedTextLength();
   d.getComputedTextLength();
   e.getComputedTextLength();
   f.getComputedTextLength();
+  g.getComputedTextLength();
 }
 </script>
--- a/layout/svg/nsSVGSwitchFrame.cpp
+++ b/layout/svg/nsSVGSwitchFrame.cpp
@@ -134,30 +134,33 @@ nsIFrame* nsSVGSwitchFrame::GetFrameForP
       point = m.TransformPoint(point);
     }
     return svgFrame->GetFrameForPoint(point);
   }
 
   return nullptr;
 }
 
+static bool shouldReflowSVGTextFrameInside(nsIFrame* aFrame) {
+  return aFrame->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer) ||
+         aFrame->IsSVGForeignObjectFrame() ||
+         !aFrame->IsFrameOfType(nsIFrame::eSVG);
+}
+
 void nsSVGSwitchFrame::AlwaysReflowSVGTextFrameDoForOneKid(nsIFrame* aKid) {
   if (!NS_SUBTREE_DIRTY(aKid)) {
     return;
   }
 
-  LayoutFrameType type = aKid->Type();
-  if (type == LayoutFrameType::SVGText) {
+  if (aKid->IsSVGTextFrame()) {
     MOZ_ASSERT(!aKid->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY),
                "A non-display SVGTextFrame directly contained in a display "
                "container?");
     static_cast<SVGTextFrame*>(aKid)->ReflowSVG();
-  } else if (aKid->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer) ||
-             type == LayoutFrameType::SVGForeignObject ||
-             !aKid->IsFrameOfType(nsIFrame::eSVG)) {
+  } else if (shouldReflowSVGTextFrameInside(aKid)) {
     if (!aKid->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
       for (nsIFrame* kid : aKid->PrincipalChildList()) {
         AlwaysReflowSVGTextFrameDoForOneKid(kid);
       }
     } else {
       // This child is in a nondisplay context, something like:
       // <switch>
       //   ...
@@ -217,16 +220,20 @@ void nsSVGSwitchFrame::ReflowSVG() {
     MOZ_ASSERT(!(child->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
                "Check for this explicitly in the |if|, then");
     svgChild->ReflowSVG();
 
     // We build up our child frame overflows here instead of using
     // nsLayoutUtils::UnionChildOverflow since SVG frame's all use the same
     // frame list, and we're iterating over that list now anyway.
     ConsiderChildOverflow(overflowRects, child);
+  } else if (child && shouldReflowSVGTextFrameInside(child)) {
+    MOZ_ASSERT(child->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY),
+               "Check for this explicitly in the |if|, then");
+    ReflowSVGNonDisplayText(child);
   }
 
   if (isFirstReflow) {
     // Make sure we have our filter property (if any) before calling
     // FinishAndStoreOverflow (subsequent filter changes are handled off
     // nsChangeHint_UpdateEffects):
     SVGObserverUtils::UpdateEffects(this);
   }
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2691,17 +2691,17 @@ pref("security.notification_enable_delay
 
 #if defined(DEBUG) && !defined(ANDROID)
 pref("csp.about_uris_without_csp", "blank,printpreview,srcdoc,about,addons,cache-entry,config,crashes,debugging,devtools,downloads,home,memory,networking,newtab,performance,plugins,policies,profiles,restartrequired,serviceworkers,sessionrestore,support,sync-log,telemetry,url-classifier,webrtc,welcomeback");
 // the following prefs are for testing purposes only.
 pref("csp.overrule_about_uris_without_csp_whitelist", false);
 pref("csp.skip_about_page_has_csp_assert", false);
 // assertion flag will be set to false after fixing Bug 1473549
 pref("security.allow_eval_with_system_principal", false);
-pref("security.uris_using_eval_with_system_principal", "autocomplete.xml,redux.js,react-redux.js,content-task.js,content-task.js,tree.xml,dialog.xml,preferencesbindings.js,wizard.xml,lodash.js,jszip.js,sinon-7.2.7.js,ajv-4.1.1.js,updates.js,setup,jsol.js,parent_utils.js,chrometask_chromescript");
+pref("security.uris_using_eval_with_system_principal", "autocomplete.xml,redux.js,react-redux.js,content-task.js,content-task.js,tree.xml,dialog.xml,preferencesbindings.js,lodash.js,jszip.js,sinon-7.2.7.js,ajv-4.1.1.js,updates.js,setup,jsol.js,parent_utils.js,chrometask_chromescript");
 #endif
 
 // Default Content Security Policy to apply to signed contents.
 pref("security.signed_content.CSP.default", "script-src 'self'; style-src 'self'");
 
 // Mixed content blocking
 pref("security.mixed_content.block_active_content", false);
 pref("security.mixed_content.block_display_content", false);
--- a/python/mozboot/mozboot/base.py
+++ b/python/mozboot/mozboot/base.py
@@ -668,17 +668,17 @@ class BaseBootstrapper(object):
     def ensure_rust_modern(self):
         cargo_home, cargo_bin = self.cargo_home()
         modern, version = self.is_rust_modern(cargo_bin)
 
         if modern:
             print('Your version of Rust (%s) is new enough.' % version)
             rustup = self.which('rustup', cargo_bin)
             if rustup:
-                self.ensure_rust_targets(rustup)
+                self.ensure_rust_targets(rustup, version)
             return
 
         if version:
             print('Your version of Rust (%s) is too old.' % version)
 
         rustup = self.which('rustup', cargo_bin)
         if rustup:
             rustup_version = self._parse_version(rustup)
@@ -692,32 +692,36 @@ class BaseBootstrapper(object):
             if not modern:
                 print(RUST_UPGRADE_FAILED % (MODERN_RUST_VERSION, after))
                 sys.exit(1)
         else:
             # No rustup. Download and run the installer.
             print('Will try to install Rust.')
             self.install_rust()
 
-    def ensure_rust_targets(self, rustup):
+    def ensure_rust_targets(self, rustup, rust_version):
         """Make sure appropriate cross target libraries are installed."""
         target_list = subprocess.check_output([rustup, 'target', 'list'])
         targets = [line.split()[0] for line in target_list.splitlines()
                    if 'installed' in line or 'default' in line]
         print('Rust supports %s targets.' % ', '.join(targets))
 
         # Support 32-bit Windows on 64-bit Windows.
         win32 = 'i686-pc-windows-msvc'
         win64 = 'x86_64-pc-windows-msvc'
         if rust.platform() == win64 and win32 not in targets:
             subprocess.check_call([rustup, 'target', 'add', win32])
 
         if 'mobile_android' in self.application:
             # Let's add the most common targets.
-            android_targets = ('thumbv7neon-linux-androideabi',
+            if LooseVersion(rust_version) < '1.33':
+                arm_target = 'armv7-linux-androideabi'
+            else:
+                arm_target = 'thumbv7neon-linux-androideabi'
+            android_targets = (arm_target,
                                'aarch64-linux-android',
                                'i686-linux-android',
                                'x86_64-linux-android', )
             for target in android_targets:
                 if target not in targets:
                     subprocess.check_call([rustup, 'target', 'add', target])
 
     def upgrade_rust(self, rustup):
--- a/taskcluster/ci/source-test/clang.yml
+++ b/taskcluster/ci/source-test/clang.yml
@@ -1,9 +1,14 @@
 job-defaults:
+    # Run only on try and code-review tasks
+    # to avoid running clang tools on the whole codebase
+    run-on-projects:
+        - try
+
     platform: linux64/opt
     attributes:
         code-review: true
     worker-type:
         by-platform:
             linux64.*: aws-provisioner-v1/gecko-t-linux-xlarge
     worker:
         docker-image: {in-tree: debian7-amd64-build}
--- a/testing/raptor/raptor/tests/raptor-tp6-8-404.ini
+++ b/testing/raptor/raptor/tests/raptor-tp6-8-404.ini
@@ -12,17 +12,16 @@ playback_binary_manifest = mitmproxy-rel
 page_cycles = 25
 unit = ms
 lower_is_better = true
 alert_threshold = 2.0
 page_timeout = 30000
 gecko_profile_interval = 1
 gecko_profile_entries = 2000000
 alert_on = fcp, loadtime
-screen_capture=true
 
 [raptor-tp6-ebay-mitm-404-recordings-202-firefox]
 apps = firefox
 test_url = https://www.ebay.com/
 playback_pageset_manifest = mitmproxy-recordings-raptor-ebay.manifest
 playback_recordings = ebay.mp
 measure = fnbpaint, fcp, dcf, loadtime
 
--- a/toolkit/components/normandy/lib/NormandyApi.jsm
+++ b/toolkit/components/normandy/lib/NormandyApi.jsm
@@ -50,21 +50,22 @@ var NormandyApi = {
     return this.apiCall("get", endpoint, data);
   },
 
   post(endpoint, data) {
     return this.apiCall("post", endpoint, data);
   },
 
   absolutify(url) {
+    if (url.startsWith("http")) {
+      return url;
+    }
     const apiBase = prefs.getCharPref("api_url");
     const server = new URL(apiBase).origin;
-    if (url.startsWith("http")) {
-      return url;
-    } else if (url.startsWith("/")) {
+    if (url.startsWith("/")) {
       return server + url;
     }
     throw new Error("Can't use relative urls");
   },
 
   async getApiUrl(name) {
     if (!indexPromise) {
       const apiBase = new URL(prefs.getCharPref("api_url"));
@@ -82,60 +83,75 @@ var NormandyApi = {
   },
 
   async fetchSignedObjects(type, filters) {
     const signedObjectsUrl = await this.getApiUrl(`${type}-signed`);
     const objectsResponse = await this.get(signedObjectsUrl, filters);
     const rawText = await objectsResponse.text();
     const objectsWithSigs = JSON.parse(rawText);
 
-    const verifiedObjects = [];
-
-    for (const objectWithSig of objectsWithSigs) {
-      const {signature, x5u} = objectWithSig.signature;
-      const object = objectWithSig[type];
-
-      const serialized = CanonicalJSON.stringify(object);
-      // Check that the rawtext (the object and the signature)
-      // includes the CanonicalJSON version of the object. This isn't
-      // strictly needed, but it is a great benefit for debugging
-      // signature problems.
-      if (!rawText.includes(serialized)) {
-        log.debug(rawText, serialized);
-        throw new NormandyApi.InvalidSignatureError(
-          `Canonical ${type} serialization does not match!`);
-      }
-
-      const certChainResponse = await this.get(this.absolutify(x5u));
-      const certChain = await certChainResponse.text();
-      const builtSignature = `p384ecdsa=${signature}`;
+    return Promise.all(
+      objectsWithSigs.map(async (item) => {
+        // Check that the rawtext (the object and the signature)
+        // includes the CanonicalJSON version of the object. This isn't
+        // strictly needed, but it is a great benefit for debugging
+        // signature problems.
+        const object = item[type];
+        const serialized = CanonicalJSON.stringify(object);
+        if (!rawText.includes(serialized)) {
+          log.debug(rawText, serialized);
+          throw new NormandyApi.InvalidSignatureError(
+            `Canonical ${type} serialization does not match!`);
+        }
+        // Verify content signature using cryptography (will throw if fails).
+        await this.verifyObjectSignature(serialized, item.signature, type);
+        return object;
+      })
+    );
+  },
 
-      const verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
-        .createInstance(Ci.nsIContentSignatureVerifier);
+  /**
+   * Verify content signature, by serializing the specified `object` as
+   * canonical JSON, and using the Normandy signer verifier to check that
+   * it matches the signature specified in `signaturePayload`.
+   *
+   * @param {object|String} data The object (or string) to be checked
+   * @param {object} signaturePayload The signature information
+   * @param {String} signaturePayload.x5u The certificate chain URL
+   * @param {String} signaturePayload.signature base64 signature bytes
+   * @param {String} type The object type (eg. `"recipe"`, `"action"`)
+   *
+   * @throws {NormandyApi.InvalidSignatureError} if signature is invalid.
+   */
+  async verifyObjectSignature(data, signaturePayload, type) {
+    const { signature, x5u } = signaturePayload;
+    const certChainResponse = await this.get(this.absolutify(x5u));
+    const certChain = await certChainResponse.text();
+    const builtSignature = `p384ecdsa=${signature}`;
 
-      let valid;
-      try {
-        valid = verifier.verifyContentSignature(
-          serialized,
-          builtSignature,
-          certChain,
-          "normandy.content-signature.mozilla.org"
-        );
-      } catch (err) {
-        throw new NormandyApi.InvalidSignatureError(`${type} signature validation failed: ${err}`);
-      }
+    const serialized = typeof data == "string" ? data : CanonicalJSON.stringify(data);
+
+    const verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
+      .createInstance(Ci.nsIContentSignatureVerifier);
 
-      if (!valid) {
-        throw new NormandyApi.InvalidSignatureError(`${type} signature is not valid`);
-      }
-
-      verifiedObjects.push(object);
+    let valid;
+    try {
+      valid = verifier.verifyContentSignature(
+        serialized,
+        builtSignature,
+        certChain,
+        "normandy.content-signature.mozilla.org"
+      );
+    } catch (err) {
+      throw new NormandyApi.InvalidSignatureError(`${type} signature validation failed: ${err}`);
     }
 
-    return verifiedObjects;
+    if (!valid) {
+      throw new NormandyApi.InvalidSignatureError(`${type} signature is not valid`);
+    }
   },
 
   /**
    * Fetch metadata about this client determined by the server.
    * @return {object} Metadata specified by the server
    */
   async classifyClient() {
     const classifyClientUrl = await this.getApiUrl("classify-client");
--- a/toolkit/components/normandy/lib/RecipeRunner.jsm
+++ b/toolkit/components/normandy/lib/RecipeRunner.jsm
@@ -45,17 +45,17 @@ const PREFS_TO_WATCH = [
   RUN_INTERVAL_PREF,
   TELEMETRY_ENABLED_PREF,
   SHIELD_ENABLED_PREF,
   API_URL_PREF,
 ];
 
 XPCOMUtils.defineLazyGetter(this, "gRemoteSettingsClient", () => {
   return RemoteSettings(REMOTE_SETTINGS_COLLECTION, {
-    filterFunc: async recipe => (await RecipeRunner.checkFilter(recipe)) ? recipe : null,
+    filterFunc: async entry => (await RecipeRunner.checkFilter(entry.recipe)) ? entry : null,
   });
 });
 
 /**
  * cacheProxy returns an object Proxy that will memoize properties of the target.
  */
 function cacheProxy(target) {
   const cache = new Map();
@@ -210,17 +210,25 @@ var RecipeRunner = {
       }
     }
 
     // Fetch recipes before execution in case we fail and exit early.
     let recipesToRun;
     try {
       recipesToRun = await this.loadRecipes();
     } catch (e) {
-      // The legacy call to `Normandy.fetchRecipes()` can throw.
+      // Either we failed at fetching the recipes from server (legacy),
+      // or the recipes signature verification failed.
+      let status = Uptake.RUNNER_SERVER_ERROR;
+      if (/NetworkError/.test(e)) {
+        status = Uptake.RUNNER_NETWORK_ERROR;
+      } else if (e instanceof NormandyApi.InvalidSignatureError) {
+        status = Uptake.RUNNER_INVALID_SIGNATURE;
+      }
+      await Uptake.reportRunner(status);
       return;
     }
 
     const actions = new ActionsManager();
     await actions.fetchRemoteActions();
     await actions.preExecution();
 
     // Execute recipes, if we have any.
@@ -237,39 +245,38 @@ var RecipeRunner = {
     await Uptake.reportRunner(Uptake.RUNNER_SUCCESS);
   },
 
   /**
    * Return the list of recipes to run, filtered for the current environment.
    */
   async loadRecipes() {
     // If RemoteSettings is enabled, we read the list of recipes from there.
-    // The JEXL filtering is done via the provided callback.
+    // The JEXL filtering is done via the provided callback (see `gRemoteSettingsClient`).
     if (await FeatureGate.isEnabled("normandy-remote-settings")) {
-      return gRemoteSettingsClient.get();
+      // First, fetch recipes whose JEXL filters match.
+      const entries = await gRemoteSettingsClient.get();
+      // Then, verify the signature of each recipe. It will throw if invalid.
+      return Promise.all(entries.map(async ( { recipe, signature } ) => {
+        await NormandyApi.verifyObjectSignature(recipe, signature, "recipe");
+        return recipe;
+      }));
     }
+
     // Obtain the recipes from the Normandy server (legacy).
     let recipes;
     try {
       recipes = await NormandyApi.fetchRecipes({enabled: true});
       log.debug(
         `Fetched ${recipes.length} recipes from the server: ` +
         recipes.map(r => r.name).join(", ")
       );
     } catch (e) {
       const apiUrl = Services.prefs.getCharPref(API_URL_PREF);
       log.error(`Could not fetch recipes from ${apiUrl}: "${e}"`);
-
-      let status = Uptake.RUNNER_SERVER_ERROR;
-      if (/NetworkError/.test(e)) {
-        status = Uptake.RUNNER_NETWORK_ERROR;
-      } else if (e instanceof NormandyApi.InvalidSignatureError) {
-        status = Uptake.RUNNER_INVALID_SIGNATURE;
-      }
-      await Uptake.reportRunner(status);
       throw e;
     }
     // Evaluate recipe filters
     const recipesToRun = [];
     for (const recipe of recipes) {
       if (await this.checkFilter(recipe)) {
         recipesToRun.push(recipe);
       }
--- a/toolkit/components/normandy/test/browser/browser_RecipeRunner.js
+++ b/toolkit/components/normandy/test/browser/browser_RecipeRunner.js
@@ -200,53 +200,98 @@ decorate_task(
 );
 
 decorate_task(
   withPrefEnv({
     set: [
       ["features.normandy-remote-settings.enabled", true],
     ],
   }),
+  withStub(NormandyApi, "verifyObjectSignature"),
   withStub(ActionsManager.prototype, "runRecipe"),
   withStub(ActionsManager.prototype, "fetchRemoteActions"),
   withStub(ActionsManager.prototype, "finalize"),
   withStub(Uptake, "reportRecipe"),
   async function testReadFromRemoteSettings(
+    verifyObjectSignatureStub,
     runRecipeStub,
     fetchRemoteActionsStub,
     finalizeStub,
     reportRecipeStub,
   ) {
-    const matchRecipe = { id: "match", action: "matchAction", filter_expression: "true", _status: "synced", enabled: true };
-    const noMatchRecipe = { id: "noMatch", action: "noMatchAction", filter_expression: "false", _status: "synced", enabled: true };
-    const missingRecipe = { id: "missing", action: "missingAction", filter_expression: "true", _status: "synced", enabled: true };
+    const matchRecipe =  { name: "match", action: "matchAction", filter_expression: "true" };
+    const noMatchRecipe = { name: "noMatch", action: "noMatchAction", filter_expression: "false" };
+    const missingRecipe = { name: "missing", action: "missingAction", filter_expression: "true" };
 
     const rsCollection = await RecipeRunner._remoteSettingsClientForTesting.openCollection();
-    await rsCollection.create(matchRecipe, { synced: true });
-    await rsCollection.create(noMatchRecipe, { synced: true });
-    await rsCollection.create(missingRecipe, { synced: true });
+    await rsCollection.clear();
+    const fakeSig = { signature: "abc" };
+    await rsCollection.create({ id: "match", recipe: matchRecipe, signature: fakeSig }, { synced: true });
+    await rsCollection.create({ id: "noMatch", recipe: noMatchRecipe, signature: fakeSig }, { synced: true });
+    await rsCollection.create({ id: "missing", recipe: missingRecipe, signature: fakeSig }, { synced: true });
     await rsCollection.db.saveLastModified(42);
     rsCollection.db.close();
 
     await RecipeRunner.run();
 
     Assert.deepEqual(
+      verifyObjectSignatureStub.args,
+      [[matchRecipe, fakeSig, "recipe"], [missingRecipe, fakeSig, "recipe"]],
+      "recipes with matching filters should have their signature verified",
+    );
+    Assert.deepEqual(
       runRecipeStub.args,
       [[matchRecipe], [missingRecipe]],
-      "recipe with matching filters should be executed",
+      "recipes with matching filters should be executed",
     );
     Assert.deepEqual(
       reportRecipeStub.args,
       [[noMatchRecipe, Uptake.RECIPE_DIDNT_MATCH_FILTER]],
       "Filtered-out recipes should be reported",
     );
   }
 );
 
 decorate_task(
+  withPrefEnv({
+    set: [
+      ["features.normandy-remote-settings.enabled", true],
+    ],
+  }),
+  withStub(ActionsManager.prototype, "runRecipe"),
+  withStub(NormandyApi, "get"),
+  withStub(Uptake, "reportRunner"),
+  async function testBadSignatureFromRemoteSettings(
+    runRecipeStub,
+    normandyGetStub,
+    reportRunnerStub,
+  ) {
+    normandyGetStub.resolves({ async text() { return "---CERT x5u----"; } });
+
+    const matchRecipe = { name: "badSig", action: "matchAction", filter_expression: "true" };
+
+    const rsCollection = await RecipeRunner._remoteSettingsClientForTesting.openCollection();
+    await rsCollection.clear();
+    const badSig = { x5u: "http://localhost/x5u", signature: "abc" };
+    await rsCollection.create({ id: "badSig", recipe: matchRecipe, signature: badSig }, { synced: true });
+    await rsCollection.db.saveLastModified(42);
+    rsCollection.db.close();
+
+    await RecipeRunner.run();
+
+    ok(!runRecipeStub.called, "no recipe is executed");
+    Assert.deepEqual(
+      reportRunnerStub.args,
+      [[Uptake.RUNNER_INVALID_SIGNATURE]],
+      "RecipeRunner should report uptake telemetry",
+    );
+  }
+);
+
+decorate_task(
   withMockNormandyApi,
   async function testRunFetchFail(mockApi) {
     const reportRunner = sinon.stub(Uptake, "reportRunner");
 
     const action = {name: "action"};
     mockApi.actions = [action];
     mockApi.fetchRecipes.rejects(new Error("Signature not valid"));
 
--- a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini
+++ b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini
@@ -36,17 +36,16 @@ support-files =
   cache.sjs
   features.js
 
 [test_classifier.html]
 skip-if = (os == 'linux' && debug) #Bug 1199778
 [test_classifier_match.html]
 [test_classifier_worker.html]
 [test_classify_by_default.html]
-skip-if = (os == 'android') #Bug 1538662
 [test_classify_ping.html]
 skip-if = (verify && debug && (os == 'win' || os == 'mac'))
 [test_classify_track.html]
 [test_gethash.html]
 [test_bug1254766.html]
 [test_cachemiss.html]
 skip-if = verify
 [test_annotation_vs_TP.html]
--- a/toolkit/components/url-classifier/tests/mochitest/test_classify_by_default.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_classify_by_default.html
@@ -9,19 +9,16 @@
 
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1442496">Mozilla Bug 1442496</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 
-<iframe id="testFrame1"></iframe>
-<iframe id="testFrame2"></iframe>
-
 <script class="testbody" type="text/javascript">
 
 // To add a request to test, add the request in trackerFrame.html
 // and the id of query string "?id=xxx" here.
 const trackersAll = [
   "img-src",
   "object-data",
   "script-src",
@@ -39,56 +36,57 @@ const trackerFrame = "http://itisatracke
 
 // This function ask the server to set the cookie
 function setup() {
   return fetch(trackerFrame + "?init=" + trackersAll.length, {
     credentials: "include",
   });
 }
 
-function loadTestFrame(withcookie, frameId) {
+function loadTestWindow(withcookie) {
   return new Promise(resolve => {
+    let win;
     let query = withcookie ? "with-cookie" : "without-cookie";
     fetch(trackerFrame + "?callback=" + query, {
       credentials: "include",
     }).then(r => {
       r.text().then((body) => {
         let trackers_found = body.split(",");
         for (let tracker of trackersAll) {
           let description = "Tracker request " + tracker + "received " +
             (withcookie ? "with" : "without") + " cookie";
           ok(trackers_found.includes(tracker), description);
         }
+        win.close();
         resolve();
       });
     });
 
-    let frame = document.getElementById(frameId);
-    frame.src = "trackerFrame.html";
+    win = window.open("trackerFrame.html");
   });
 }
 
 async function runTests() {
   await SpecialPowers.pushPrefEnv({set: [
     [ "urlclassifier.trackingAnnotationTable.testEntries", "itisatracker.org" ],
     [ "network.cookie.cookieBehavior", 4],
     [ "privacy.trackingprotection.enabled", false ],
     [ "privacy.trackingprotection.annotate_channels", false],
     [ "browser.send_pings", true],
   ]});
 
   await setup();
 
-  await loadTestFrame(true, "testFrame1");
+  await loadTestWindow(true);
 
   await SpecialPowers.pushPrefEnv({set: [
     [ "privacy.trackingprotection.annotate_channels", true],
   ]});
 
-  await loadTestFrame(false, "testFrame2");
+  await loadTestWindow(false);
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 runTests();
 
 </script>
--- a/toolkit/content/widgets/wizard.xml
+++ b/toolkit/content/widgets/wizard.xml
@@ -439,28 +439,17 @@
         <parameter name="aTarget"/>
         <parameter name="aType"/>
         <body>
         <![CDATA[
           var event = document.createEvent("Events");
           event.initEvent(aType, true, true);
 
           // handle dom event handlers
-          var noCancel = aTarget.dispatchEvent(event);
-
-          // handle any xml attribute event handlers
-          var handler = aTarget.getAttribute("on"+aType);
-          if (handler != "") {
-            var fn = new Function("event", handler);
-            var returned = fn.apply(aTarget, [event]);
-            if (returned == false)
-              noCancel = false;
-          }
-
-          return noCancel;
+          return aTarget.dispatchEvent(event);
         ]]>
         </body>
       </method>
 
     </implementation>
 
     <handlers>
       <handler event="keypress" keycode="VK_RETURN"
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -303,16 +303,40 @@ var gUpdates = {
     }
 
     // Cache the standard button labels in case we need to restore them
     this._cacheButtonStrings("next");
     this._cacheButtonStrings("finish");
     this._cacheButtonStrings("extra1");
     this._cacheButtonStrings("extra2");
 
+    document.addEventListener("wizardfinish", function() { gUpdates.onWizardFinish(); });
+    document.addEventListener("wizardcancel", function() { gUpdates.onWizardCancel(); });
+    document.addEventListener("wizardnext", function() { gUpdates.onWizardNext(); });
+
+    document.getElementById("checking").addEventListener("pageshow", function() { gCheckingPage.onPageShow(); });
+    document.getElementById("noupdatesfound").addEventListener("pageshow", function() { gNoUpdatesPage.onPageShow(); });
+    document.getElementById("manualUpdate").addEventListener("pageshow", function() { gManualUpdatePage.onPageShow(); });
+    document.getElementById("unsupported").addEventListener("pageshow", function() { gUnsupportedPage.onPageShow(); });
+    document.getElementById("updatesfoundbasic").addEventListener("pageshow", function() { gUpdatesFoundBasicPage.onPageShow(); });
+    document.getElementById("downloading").addEventListener("pageshow", function() { gDownloadingPage.onPageShow(); });
+    document.getElementById("errors").addEventListener("pageshow", function() { gErrorsPage.onPageShow(); });
+    document.getElementById("errorextra").addEventListener("pageshow", function() { gErrorExtraPage.onPageShow(); });
+    document.getElementById("errorpatching").addEventListener("pageshow", function() { gErrorPatchingPage.onPageShow(); });
+    document.getElementById("finished").addEventListener("pageshow", function() { gFinishedPage.onPageShow(); });
+    document.getElementById("finishedBackground").addEventListener("pageshow", function() { gFinishedPage.onPageShowBackground(); });
+
+    document.getElementById("updatesfoundbasic").addEventListener("extra1", function() { gUpdatesFoundBasicPage.onExtra1(); });
+    document.getElementById("downloading").addEventListener("extra1", function() { gDownloadingPage.onHide(); });
+    document.getElementById("finished").addEventListener("extra1", function() { gFinishedPage.onExtra1(); });
+    document.getElementById("finishedBackground").addEventListener("extra1", function() { gFinishedPage.onExtra1(); });
+
+    document.getElementById("updatesfoundbasic").addEventListener("extra2", function() { gUpdatesFoundBasicPage.onExtra2(); });
+    document.getElementById("finishedBackground").addEventListener("extra2", function() { gFinishedPage.onExtra2(); });
+
     // Advance to the Start page.
     this.getStartPageID(function(startPageID) {
       LOG("gUpdates", "onLoad - setting current page to startpage " + startPageID);
       gUpdates.wiz.currentPage = document.getElementById(startPageID);
     });
   },
 
   /**
--- a/toolkit/mozapps/update/content/updates.xul
+++ b/toolkit/mozapps/update/content/updates.xul
@@ -19,19 +19,16 @@
 ]>
 
 <wizard id="updates"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         title="&updateWizard.title;"
         windowtype="Update:Wizard"
         style="width: auto; height: auto"
-        onwizardfinish="gUpdates.onWizardFinish();"
-        onwizardcancel="gUpdates.onWizardCancel();"
-        onwizardnext="gUpdates.onWizardNext();"
         onload="gUpdates.onLoad();"
         onunload="gUpdates.onUnload();">
 
   <script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
   <script type="application/javascript" src="chrome://mozapps/content/update/updates.js"/>
   <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="application/javascript" src="chrome://global/content/editMenuOverlay.js"/>
 
@@ -42,68 +39,63 @@
   <stringbundleset id="updateSet">
     <stringbundle id="brandStrings" src="chrome://branding/locale/brand.properties"/>
     <stringbundle id="updateStrings" src="chrome://mozapps/locale/update/updates.properties"/>
   </stringbundleset>
 
   <wizardpage id="dummy" pageid="dummy" firstpage="true"/>
 
   <wizardpage id="checking" pageid="checking" next="noupdatesfound"
-              object="gCheckingPage" onpageshow="gCheckingPage.onPageShow();">
+              object="gCheckingPage">
     <updateheader label="&checking.title;"/>
     <vbox class="update-content" flex="1">
       <label>&updateCheck.label;</label>
       <separator class="thin"/>
       <html:progress id="checkingProgress"/>
     </vbox>
   </wizardpage>
 
   <wizardpage id="noupdatesfound" pageid="noupdatesfound"
-              object="gNoUpdatesPage" onpageshow="gNoUpdatesPage.onPageShow();">
+              object="gNoUpdatesPage">
     <updateheader label="&noupdatesfound.title;"/>
     <vbox class="update-content" flex="1">
       <label id="noUpdatesAutoEnabled" hidden="true">&noupdatesautoenabled.intro;</label>
       <label id="noUpdatesAutoDisabled" hidden="true">&noupdatesautodisabled.intro;</label>
     </vbox>
   </wizardpage>
 
-  <wizardpage id="manualUpdate" pageid="manualUpdate" object="gManualUpdatePage"
-              onpageshow="gManualUpdatePage.onPageShow();">
+  <wizardpage id="manualUpdate" pageid="manualUpdate" object="gManualUpdatePage">
     <updateheader label="&manualUpdate.title;"/>
     <vbox class="update-content" flex="1">
       <label id="manualUpdateDesc">&manualUpdate.desc;</label>
       <label id="manualUpdateSpaceDesc"
              hidden="true">&manualUpdate.space.desc;</label>
       <separator class="thin"/>
       <label>&manualUpdateGetMsg.label;</label>
       <hbox>
         <label id="manualUpdateLinkLabel" value="" is="text-link"
                onclick="openUpdateURL(event);"/>
       </hbox>
     </vbox>
   </wizardpage>
 
   <wizardpage id="unsupported" pageid="unsupported"
-              object="gUnsupportedPage"
-              onpageshow="gUnsupportedPage.onPageShow();">
+              object="gUnsupportedPage">
     <updateheader label="&unsupported.title;"/>
     <vbox class="update-content" flex="1">
       <description flex="1">&unsupported.label;
         <label id="unsupportedLinkLabel" class="inline-link" onclick="openUpdateURL(event);" is="text-link">
           &unsupportedLink.label;
         </label>
       </description>
     </vbox>
   </wizardpage>
 
   <wizardpage id="updatesfoundbasic" pageid="updatesfoundbasic"
-              object="gUpdatesFoundBasicPage" next="downloading"
-              onpageshow="gUpdatesFoundBasicPage.onPageShow();"
-              onextra1="gUpdatesFoundBasicPage.onExtra1();"
-              onextra2="gUpdatesFoundBasicPage.onExtra2();">
+              object="gUpdatesFoundBasicPage" next="downloading">
     <updateheader id="updatesFoundBasicHeader" label=""/>
     <vbox class="update-content" flex="1">
       <label id="updatesFoundInto"/>
       <separator class="thin"/>
       <label id="updateName" crop="right" value=""/>
       <separator id="updateNameSep" class="thin"/>
       <label id="upgradeEvangelism">&evangelism.desc;</label>
       <separator id="upgradeEvangelismSep" flex="1"/>
@@ -112,18 +104,17 @@
           <label id="updateMoreInfoURL" is="text-link"
                  value="&clickHere.label;" onclick="openUpdateURL(event);"/>
         </hbox>
       </vbox>
     </vbox>
   </wizardpage>
 
   <wizardpage id="downloading" pageid="downloading"
-              object="gDownloadingPage" onextra1="gDownloadingPage.onHide();"
-              onpageshow="gDownloadingPage.onPageShow();">
+              object="gDownloadingPage">
     <updateheader label="&downloadPage.title;"/>
     <vbox class="update-content" flex="1">
       <hbox id="downloadStatusProgress">
         <html:progress id="downloadProgress" max="100"/>
         <button id="pauseButton" oncommand="gDownloadingPage.onPause();"
                 paused="false"/>
       </hbox>
       <separator class="thin"/>
@@ -133,67 +124,60 @@
       <separator/>
       <hbox id="verificationFailed" align="start" hidden="true">
         <image id="verificationFailedIcon"/>
         <label flex="1">&verificationFailedText.label;</label>
       </hbox>
     </vbox>
   </wizardpage>
 
-  <wizardpage id="errors" pageid="errors" object="gErrorsPage"
-              onpageshow="gErrorsPage.onPageShow();">
+  <wizardpage id="errors" pageid="errors" object="gErrorsPage">
     <updateheader label="&error.title;"/>
     <vbox class="update-content" flex="1">
       <label id="errorIntro">&error.label;</label>
       <separator/>
       <html:textarea class="plain" readonly="readonly" id="errorReason" rows="3"/>
       <separator/>
       <label id="errorManual">&errorManual.label;</label>
       <hbox>
         <label id="errorLinkLabel" value="" is="text-link"
                onclick="openUpdateURL(event);"/>
       </hbox>
     </vbox>
   </wizardpage>
 
   <wizardpage id="errorextra" pageid="errorextra"
-              object="gErrorExtraPage"
-              onpageshow="gErrorExtraPage.onPageShow();">
+              object="gErrorExtraPage">
     <updateheader label="&error.title;"/>
     <vbox class="update-content" flex="1">
       <label id="bgErrorLabel">&genericBackgroundError.label;</label>
       <hbox>
         <label id="errorExtraLinkLabel" is="text-link"
                value="" onclick="openUpdateURL(event);"/>
       </hbox>
     </vbox>
   </wizardpage>
 
   <wizardpage id="errorpatching" pageid="errorpatching" next="downloading"
-              object="gErrorPatchingPage"
-              onpageshow="gErrorPatchingPage.onPageShow();">
+              object="gErrorPatchingPage">
     <updateheader label="&error.title;"/>
     <vbox class="update-content" flex="1">
       <label>&errorpatching.intro;</label>
     </vbox>
   </wizardpage>
 
-  <wizardpage id="finished" pageid="finished" object="gFinishedPage"
-              onpageshow="gFinishedPage.onPageShow();"
-              onextra1="gFinishedPage.onExtra1()">
+  <wizardpage id="finished" pageid="finished" object="gFinishedPage">
     <updateheader label="&finishedPage.title;"/>
     <vbox class="update-content" flex="1">
       <label>&finishedPage.text;</label>
     </vbox>
   </wizardpage>
 
   <wizardpage id="finishedBackground" pageid="finishedBackground"
-              object="gFinishedPage" onextra1="gFinishedPage.onExtra1()"
-              onextra2="gFinishedPage.onExtra2()"
-              onpageshow="gFinishedPage.onPageShowBackground();">
+              object="gFinishedPage">
     <updateheader label="&finishedPage.title;"/>
     <vbox class="update-content" flex="1">
       <label>&finishedBackgroundPage.text;</label>
       <separator/>
       <hbox align="center">
         <label>&finishedBackground.name;</label>
         <label id="updateFinishedName" flex="1" crop="right" value=""/>
         <label id="finishedBackgroundLink" disabled="true" is="text-link"
--- a/toolkit/profile/content/createProfileWizard.js
+++ b/toolkit/profile/content/createProfileWizard.js
@@ -26,16 +26,19 @@ function initWizard() {
   try {
     gProfileService = C[ToolkitProfileService].getService(I.nsIToolkitProfileService);
     gProfileManagerBundle = document.getElementById("bundle_profileManager");
 
     gDefaultProfileParent = Services.dirsvc.get("DefProfRt", I.nsIFile);
 
     // Initialize the profile location display.
     gProfileDisplay = document.getElementById("profileDisplay").firstChild;
+    document.addEventListener("wizardfinish", onFinish);
+    document.getElementById("explanation").addEventListener("pageshow", enableNextButton);
+    document.getElementById("createProfile").addEventListener("pageshow", initSecondWizardPage);
     setDisplayToDefaultFolder();
   } catch (e) {
     window.close();
     throw (e);
   }
 }
 
 // Called every time the second wizard page is displayed.
@@ -164,42 +167,40 @@ function profileExists(aName) {
   return false;
 }
 
 // Called when the first wizard page is shown.
 function enableNextButton() {
   document.documentElement.canAdvance = true;
 }
 
-function onFinish() {
+function onFinish(event) {
   var profileName = document.getElementById("profileName").value;
   var profile;
 
   // Create profile named profileName in profileRoot.
   try {
     profile = gProfileService.createProfile(gProfileRoot, profileName);
   } catch (e) {
     var profileCreationFailed =
       gProfileManagerBundle.getString("profileCreationFailed");
     var profileCreationFailedTitle =
       gProfileManagerBundle.getString("profileCreationFailedTitle");
     Services.prompt.alert(window, profileCreationFailedTitle,
                           profileCreationFailed + "\n" + e);
 
-    return false;
+    event.preventDefault();
+    return;
   }
 
   // window.opener is false if the Create Profile Wizard was opened from the
   // command line.
   if (window.opener) {
     // Add new profile to the list in the Profile Manager.
     window.opener.CreateProfile(profile);
   } else {
     // Use the newly created Profile.
     var profileLock = profile.lock(null);
 
     var dialogParams = window.arguments[0].QueryInterface(I.nsIDialogParamBlock);
     dialogParams.objects.insertElementAt(profileLock, 0);
   }
-
-  // Exit the wizard.
-  return true;
 }
--- a/toolkit/profile/content/createProfileWizard.xul
+++ b/toolkit/profile/content/createProfileWizard.xul
@@ -12,44 +12,43 @@
 %profileDTD;
 ]>
 
 <wizard id="createProfileWizard"
         title="&newprofile.title;"
         xmlns:html="http://www.w3.org/1999/xhtml"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        onwizardfinish="return onFinish();"
         onload="initWizard();"
         style="&window.size;">
   <script type="application/javascript"
           src="chrome://global/content/customElements.js"/>
 
   <stringbundle id="bundle_profileManager"
                 src="chrome://mozapps/locale/profile/profileSelection.properties"/>
 
   <script type="application/javascript" src="chrome://mozapps/content/profile/createProfileWizard.js"/>
 
-  <wizardpage id="explanation" onpageshow="enableNextButton();">
+  <wizardpage id="explanation">
     <description>&profileCreationExplanation_1.text;</description>
     <description>&profileCreationExplanation_2.text;</description>
     <description>&profileCreationExplanation_3.text;</description>
     <spacer flex="1"/>
 #ifdef XP_MACOSX
     <description>&profileCreationExplanation_4Mac.text;</description>
 #else
 #ifdef XP_UNIX
     <description>&profileCreationExplanation_4Gnome.text;</description>
 #else
     <description>&profileCreationExplanation_4.text;</description>
 #endif
 #endif
   </wizardpage>
 
-  <wizardpage id="createProfile" onpageshow="initSecondWizardPage();">
+  <wizardpage id="createProfile">
     <description>&profileCreationIntro.text;</description> 
 
     <label accesskey="&profilePrompt.accesskey;" control="ProfileName">&profilePrompt.label;</label> 
     <textbox id="profileName" value="&profileDefaultName;"
              oninput="updateProfileName(this.value);"/>
     
     <separator/>
 
--- a/tools/clang-tidy/config.yaml
+++ b/tools/clang-tidy/config.yaml
@@ -129,16 +129,17 @@ clang_checkers:
         value: 1
       - key: AllowPointerConditions
         # The check will allow conditional pointer conversions.
         value: 1
   - name: readability-inconsistent-declaration-parameter-name
   - name: readability-misleading-indentation
   - name: readability-non-const-parameter
   - name: readability-redundant-control-flow
+  - name: readability-redundant-preprocessor
   - name: readability-redundant-smartptr-get
   - name: readability-redundant-string-cstr
   - name: readability-redundant-string-init
   - name: readability-static-accessed-through-instance
   - name: readability-simplify-boolean-expr
   - name: readability-uniqueptr-delete-release
   # We don't publish the google checkers since we are interested in only having
   # a general idea how our code complies with the rules added by these checkers.
--- a/tools/code-coverage/CodeCoverageHandler.cpp
+++ b/tools/code-coverage/CodeCoverageHandler.cpp
@@ -28,17 +28,17 @@ using namespace mozilla;
 // https://github.com/gcc-mirror/gcc/blob/aad93da1a579b9ae23ede6b9cf8523360f0a08b4/libgcc/libgcov-interface.c.
 // __gcov_flush is protected by a mutex in GCC, but not in LLVM, so we are using
 // a CrossProcessMutex to protect it.
 
 // We rename __gcov_flush to __custom_llvm_gcov_flush in our build of LLVM for
 // Linux, to avoid naming clashes in builds which mix GCC and LLVM. So, when we
 // are building with LLVM exclusively, we need to use __custom_llvm_gcov_flush
 // instead.
-#if defined(XP_LINUX) && defined(__clang__)
+#if !defined(XP_WIN) && defined(__clang__)
 #  define __gcov_flush __custom_llvm_gcov_flush
 #endif
 
 extern "C" void __gcov_flush();
 
 StaticAutoPtr<CodeCoverageHandler> CodeCoverageHandler::instance;
 
 void CodeCoverageHandler::FlushCounters() {
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -22,16 +22,17 @@
 #ifdef MOZ_GECKO_PROFILER
 #  include "GeckoProfilerReporter.h"
 #endif
 #if defined(XP_UNIX) || defined(MOZ_DMD)
 #  include "nsMemoryInfoDumper.h"
 #endif
 #include "nsNetCID.h"
 #include "nsThread.h"
+#include "VRProcessManager.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReportingProcess.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/RDDProcessManager.h"
 #include "mozilla/ResultExtensions.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
@@ -1809,16 +1810,22 @@ nsresult nsMemoryReporterManager::StartG
   }
 
   if (RDDProcessManager* rdd = RDDProcessManager::Get()) {
     if (RefPtr<MemoryReportingProcess> proc = rdd->GetProcessMemoryReporter()) {
       s->mChildrenPending.AppendElement(proc.forget());
     }
   }
 
+  if (gfx::VRProcessManager* vr = gfx::VRProcessManager::Get()) {
+    if (RefPtr<MemoryReportingProcess> proc = vr->GetProcessMemoryReporter()) {
+      s->mChildrenPending.AppendElement(proc.forget());
+    }
+  }
+
   if (!mIsRegistrationBlocked && net::gIOService) {
     if (RefPtr<MemoryReportingProcess> proc =
             net::gIOService->GetSocketProcessMemoryReporter()) {
       s->mChildrenPending.AppendElement(proc.forget());
     }
   }
 
   if (!s->mChildrenPending.IsEmpty()) {
--- a/xpcom/build/components.conf
+++ b/xpcom/build/components.conf
@@ -62,17 +62,17 @@ Classes = [
         'headers': ['mozilla/nsMemoryInfoDumper.h'],
     },
     {
         'cid': '{fb97e4f5-32dd-497a-baa2-7d1e55079910}',
         'contract_ids': ['@mozilla.org/memory-reporter-manager;1'],
         'type': 'nsMemoryReporterManager',
         'headers': ['/xpcom/base/nsMemoryReporterManager.h'],
         'init_method': 'Init',
-        'processes': ProcessSelector.ALLOW_IN_GPU_AND_SOCKET_PROCESS,
+        'processes': ProcessSelector.ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS,
     },
     {
         'cid': '{7b4eeb20-d781-11d4-8a83-0010a4e0c9ca}',
         'contract_ids': ['@mozilla.org/process/util;1'],
         'type': 'nsProcess',
         'headers': ['nsProcess.h'],
     },
     {
--- a/xpcom/reflect/xptcall/md/unix/moz.build
+++ b/xpcom/reflect/xptcall/md/unix/moz.build
@@ -21,17 +21,17 @@ if CONFIG['OS_ARCH'] == 'Darwin':
 
 if CONFIG['OS_ARCH'] == 'GNU':
     if CONFIG['CPU_ARCH'] == 'x86':
         SOURCES += [
             'xptcinvoke_gcc_x86_unix.cpp',
             'xptcstubs_gcc_x86_unix.cpp'
         ]
 
-if CONFIG['OS_ARCH'] in ('Linux', 'Bitrig', 'DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD') or \
+if CONFIG['OS_ARCH'] in ('Linux', 'Bitrig', 'DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD', 'SunOS') or \
    CONFIG['OS_ARCH'].startswith('GNU_'):
     if CONFIG['CPU_ARCH'] == 'x86_64':
         SOURCES += [
             'xptcinvoke_asm_x86_64_unix.S',
             'xptcinvoke_x86_64_unix.cpp',
             'xptcstubs_x86_64_linux.cpp',
         ]
     elif CONFIG['CPU_ARCH'] == 'x86':
@@ -44,51 +44,16 @@ if CONFIG['OS_ARCH'] in ('Linux', 'FreeB
     if CONFIG['CPU_ARCH'] == 'ia64':
         SOURCES += [
             'xptcinvoke_asm_ipf64.s',
             'xptcinvoke_ipf64.cpp',
             'xptcstubs_asm_ipf64.s',
             'xptcstubs_ipf64.cpp'
         ]
 
-if CONFIG['OS_ARCH'] == 'SunOS' and CONFIG['INTEL_ARCHITECTURE']:
-    if CONFIG['CPU_ARCH'] == 'x86_64':
-        if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
-            SOURCES += [
-                'xptcinvoke_asm_x86_64_unix.S',
-                'xptcinvoke_x86_64_unix.cpp',
-                'xptcstubs_x86_64_linux.cpp'
-            ]
-        else:
-            GENERATED_FILES = [
-                'xptcstubsdef_asm.solx86',
-            ]
-            ASFLAGS += ['-xarch=amd64']
-            SOURCES += [
-                'xptcinvoke_x86_64_solaris.cpp',
-                'xptcstubs_asm_x86_64_solaris_SUNW.s',
-                'xptcstubs_x86_64_solaris.cpp',
-            ]
-    else:
-        if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
-            SOURCES += [
-                'xptcinvoke_gcc_x86_unix.cpp',
-                'xptcstubs_gcc_x86_unix.cpp'
-            ]
-        else:
-            GENERATED_FILES = [
-                'xptcstubsdef_asm.solx86',
-            ]
-            SOURCES += [
-                'xptcinvoke_asm_x86_solaris_SUNW.s',
-                'xptcinvoke_x86_solaris.cpp',
-                'xptcstubs_asm_x86_solaris_SUNW.s',
-                'xptcstubs_x86_solaris.cpp'
-            ]
-
 if CONFIG['CPU_ARCH'] == 'Alpha':
     if CONFIG['OS_ARCH'] in ('Linux', 'FreeBSD', 'NetBSD'):
         SOURCES += [
             'xptcinvoke_linux_alpha.cpp',
             'xptcstubs_linux_alpha.cpp',
         ]
     elif CONFIG['OS_ARCH'] == 'OpenBSD':
         SOURCES += [
@@ -235,53 +200,24 @@ if CONFIG['OS_ARCH'] == 'NetBSD' and CON
 if CONFIG['OS_ARCH'] == 'OpenBSD' and CONFIG['CPU_ARCH'] == 'sparc':
     SOURCES += [
         'xptcinvoke_asm_sparc_openbsd.s',
         'xptcinvoke_sparc_openbsd.cpp',
         'xptcstubs_asm_sparc_openbsd.s',
         'xptcstubs_sparc_openbsd.cpp',
     ]
 
-if CONFIG['OS_ARCH'] in ('OpenBSD', 'FreeBSD', 'Linux') and CONFIG['CPU_ARCH'] == 'sparc64':
+if CONFIG['OS_ARCH'] in ('OpenBSD', 'FreeBSD', 'Linux', 'SunOS') and CONFIG['CPU_ARCH'] == 'sparc64':
     SOURCES += [
         'xptcinvoke_asm_sparc64_openbsd.s',
         'xptcinvoke_sparc64_openbsd.cpp',
         'xptcstubs_asm_sparc64_openbsd.s',
         'xptcstubs_sparc64_openbsd.cpp',
     ]
 
-if CONFIG['OS_ARCH'] == 'SunOS' and not CONFIG['INTEL_ARCHITECTURE']:
-    if CONFIG['HAVE_64BIT_BUILD']:
-        ASFLAGS += ['-xarch=v9']
-        SOURCES += [
-            'xptcinvoke_sparcv9_solaris.cpp',
-            'xptcstubs_sparcv9_solaris.cpp',
-        ]
-    else:
-        SOURCES += [
-            'xptcinvoke_sparc_solaris.cpp',
-            'xptcstubs_sparc_solaris.cpp',
-        ]
-    if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
-        SOURCES += [
-            'xptcinvoke_asm_sparc_solaris_GCC3.s',
-            'xptcstubs_asm_sparc_solaris.s',
-        ]
-    else:
-        if CONFIG['HAVE_64BIT_BUILD']:
-            SOURCES += [
-                'xptcinvoke_asm_sparcv9_solaris_SUNW.s',
-                'xptcstubs_asm_sparcv9_solaris.s',
-            ]
-        else:
-            SOURCES += [
-                'xptcinvoke_asm_sparc_solaris_SUNW.s',
-                'xptcstubs_asm_sparc_solaris.s',
-            ]
-
 if CONFIG['OS_ARCH'] == 'Linux':
     if CONFIG['CPU_ARCH'] == 's390':
         SOURCES += [
             'xptcinvoke_linux_s390.cpp',
             'xptcstubs_linux_s390.cpp',
         ]
         CXXFLAGS += [
             '-fno-strict-aliasing',
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-/*
- * Platform specific code to invoke XPCOM methods on native objects for
- * solaris/sparc with gcc 3 ABI.
- */
-        .global NS_InvokeByIndex
-/*
- *  NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
- *                   uint32_t paramCount, nsXPTCVariant* params);
- */
-NS_InvokeByIndex:
-        save    %sp,-(64 + 32),%sp  ! room for the register window and
-                                    ! struct pointer, rounded up to 0 % 32
-        mov     %i2,%o0             ! paramCount
-        call    invoke_count_words  ! returns the required stack size in %o0
-        mov     %i3,%o1             ! params
-        
-        sll     %o0,2,%l0           ! number of bytes
-        sub     %sp,%l0,%sp         ! create the additional stack space
-            
-        mov     %sp,%o0             ! pointer for copied args
-        add     %o0,72,%o0          ! step past the register window, the
-                                    ! struct result pointer and the 'this' slot
-        mov     %i2,%o1             ! paramCount
-        call    invoke_copy_to_stack
-        mov     %i3,%o2             ! params
-!
-!   calculate the target address from the vtable
-!
-        ld      [%i0],%l1           ! *that --> vTable
-        sll     %i1,2,%i1           ! multiply index by 4
-        add     %i1,%l1,%l1         ! l1 now points to vTable entry
-        ld      [%l1],%l0           ! target address
-
-.L5:    ld      [%sp + 88],%o5
-.L4:    ld      [%sp + 84],%o4
-.L3:    ld      [%sp + 80],%o3
-.L2:    ld      [%sp + 76],%o2
-.L1:    ld      [%sp + 72],%o1
-.L0:
-        jmpl    %l0,%o7             ! call the routine
-! always have a 'this', from the incoming 'that'
-        mov     %i0,%o0
-        
-        mov     %o0,%i0             ! propagate return value
-        ret
-        restore
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s
+++ /dev/null
@@ -1,56 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-/* Platform specific code to invoke XPCOM methods on native objects */
-
-        .global NS_InvokeByIndex
-        .type   NS_InvokeByIndex, #function
-/*
-    NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
-                     uint32_t paramCount, nsXPTCVariant* params);
-    
-*/
-NS_InvokeByIndex:
-        save    %sp,-(64 + 32),%sp  ! room for the register window and
-                                    ! struct pointer, rounded up to 0 % 32
-        sll     %i2,3,%l0           ! assume the worst case
-                                    ! paramCount * 2 * 4 bytes
-        cmp     %l0, 0              ! are there any args? If not,
-        be      .invoke             ! no need to copy args to stack
-
-        sub     %sp,%l0,%sp         ! create the additional stack space
-        add     %sp,72,%o0          ! step past the register window, the
-                                    ! struct result pointer and the 'this' slot
-        mov     %i2,%o1             ! paramCount
-        call    invoke_copy_to_stack
-        mov     %i3,%o2             ! params
-
-!
-!   load arguments from stack into the outgoing registers
-!
-        ld      [%sp + 72],%o1
-        ld      [%sp + 76],%o2
-        ld      [%sp + 80],%o3
-        ld      [%sp + 84],%o4
-        ld      [%sp + 88],%o5
-
-!
-!   calculate the target address from the vtable
-!
-.invoke:
-        sll     %i1,2,%l0           ! index *= 4
-        add     %l0,8,%l0           ! there are 2 extra entries in the vTable
-        ld      [%i0],%l1           ! *that --> address of vtable
-        ld      [%l0 + %l1],%l0     ! that->vtable[index * 4 + 8] --> address
-
-        jmpl    %l0,%o7             ! call the routine
-        mov     %i0,%o0             ! move 'this' pointer to out register
-
-        mov     %o0,%i0             ! propagate return value
-        ret
-        restore
-
-        .size    NS_InvokeByIndex, .-NS_InvokeByIndex
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- Mode: asm; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
-    Platform specific code to invoke XPCOM methods on native objects
-    for sparcv9 Solaris.
-
-    See the SPARC Compliance Definition (SCD) Chapter 3
-    for more information about what is going on here, including
-    the use of BIAS (0x7ff).
-    The SCD is available from http://www.sparc.com/.
-*/
-
-        .global NS_InvokeByIndex
-        .type   NS_InvokeByIndex, #function
-
-/*
-    NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
-                     uint32_t paramCount, nsXPTCVariant* params);
-    
-*/
-NS_InvokeByIndex:
-        save    %sp,-(128 + 64),%sp ! room for the register window and
-                                    ! struct pointer, rounded up to 0 % 64
-        sll     %i2,4,%l0           ! assume the worst case
-                                    ! paramCount * 2 * 8 bytes
-        cmp     %l0, 0              ! are there any args? If not,
-        be      .invoke             ! no need to copy args to stack
-
-        sub     %sp,%l0,%sp         ! create the additional stack space
-        add     %sp,0x7ff+136,%o0   ! step past the register window, the
-                                    ! struct result pointer and the 'this' slot
-        mov     %i2,%o1             ! paramCount
-        call    invoke_copy_to_stack
-        mov     %i3,%o2             ! params
-
-!
-!   load arguments from stack into the outgoing registers
-!   BIAS is 0x7ff (2047)
-!
-
-!   load the %o1..5 64bit (extended word) output registers registers 
-        ldx     [%sp + 0x7ff + 136],%o1    ! %i1
-        ldx     [%sp + 0x7ff + 144],%o2    ! %i2
-        ldx     [%sp + 0x7ff + 152],%o3    ! %i3
-        ldx     [%sp + 0x7ff + 160],%o4    ! %i4
-        ldx     [%sp + 0x7ff + 168],%o5    ! %i5
-
-!   load the even number double registers starting with %d2
-        ldd     [%sp + 0x7ff + 136],%d2
-        ldd     [%sp + 0x7ff + 144],%d4
-        ldd     [%sp + 0x7ff + 152],%d6
-        ldd     [%sp + 0x7ff + 160],%d8
-        ldd     [%sp + 0x7ff + 168],%d10
-        ldd     [%sp + 0x7ff + 176],%d12
-        ldd     [%sp + 0x7ff + 184],%d14
-        ldd     [%sp + 0x7ff + 192],%d16
-        ldd     [%sp + 0x7ff + 200],%d18
-        ldd     [%sp + 0x7ff + 208],%d20
-        ldd     [%sp + 0x7ff + 216],%d22
-        ldd     [%sp + 0x7ff + 224],%d24
-        ldd     [%sp + 0x7ff + 232],%d26
-        ldd     [%sp + 0x7ff + 240],%d28
-        ldd     [%sp + 0x7ff + 248],%d30
-
-!
-!   calculate the target address from the vtable
-!
-.invoke:
-        sll     %i1,3,%l0           ! index *= 8
-        add     %l0,16,%l0          ! there are 2 extra entries in the vTable (16bytes)
-        ldx     [%i0],%l1           ! *that --> address of vtable
-        ldx     [%l0 + %l1],%l0     ! that->vtable[index * 8 + 16] --> address
-
-        jmpl    %l0,%o7             ! call the routine
-        mov     %i0,%o0             ! move 'this' pointer to out register
-
-        mov     %o0,%i0             ! propagate return value
-        ret
-        restore
-
-        .size    NS_InvokeByIndex, .-NS_InvokeByIndex
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_solaris_SUNW.s
+++ /dev/null
@@ -1,55 +0,0 @@
-	.globl NS_InvokeByIndex
-	.type NS_InvokeByIndex, @function
-NS_InvokeByIndex:
-	push       %ebp
-	movl       %esp,%ebp
-	push       %ebx
-	call       .CG0.66
-.CG0.66:
-	pop        %ebx
-	addl       $_GLOBAL_OFFSET_TABLE_+0x1,%ebx
-	push       20(%ebp)
-	push       16(%ebp)
-	push       12(%ebp)
-	push       8(%ebp)
-	/ INLINE: invoke_by_index
-
-
-
-	pushl	%ebx
-	pushl	%esi
-	movl	%esp, %ebx
-
-	pushl	0x14(%ebp)
-	pushl	0x10(%ebp)
-	call	invoke_count_words
-	mov	%ebx, %esp
-
-	sall	$0x2 , %eax
-	subl	%eax, %esp
-	movl	%esp, %esi
-
-	pushl	%esp
-	pushl	0x14(%ebp)
-	pushl	0x10(%ebp)
-	call	invoke_copy_to_stack
-	movl	%esi, %esp
-
-	movl	0x8(%ebp), %ecx
-	pushl	%ecx
-	movl	(%ecx), %edx
-	movl	0xc(%ebp), %eax
-	movl	0x8(%edx, %eax, 4), %edx
-
-	call	*%edx
-	mov	%ebx, %esp
-	popl	%esi
-	popl	%ebx
-	/ INLINE_END
-	addl       $16,%esp
-	pop        %ebx
-	movl       %ebp,%esp
-	pop        %ebp
-	ret        
-	.size NS_InvokeByIndex, . - NS_InvokeByIndex
-
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_sparc64_openbsd.cpp
+++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_sparc64_openbsd.cpp
@@ -25,19 +25,19 @@ invoke_copy_to_stack(uint64_t* d, uint32
   nsXPTCVariant *l_s = s;
   uint64_t l_paramCount = paramCount;
   uint64_t regCount = 0;  // return the number of registers to load from the stack
 
   for(uint64_t i = 0; i < l_paramCount; i++, l_d++, l_s++)
   {
     if (regCount < 5) regCount++;
 
-    if (l_s->IsPtrData())
+    if (l_s->IsIndirect())
     {
-      *l_d = (uint64_t)l_s->ptr;
+      *l_d = (uint64_t) &l_s->val;
       continue;
     }
     switch (l_s->type)
     {
       case nsXPTType::T_I8    : *((int64_t*)l_d)     = l_s->val.i8;    break;
       case nsXPTType::T_I16   : *((int64_t*)l_d)     = l_s->val.i16;   break;
       case nsXPTType::T_I32   : *((int64_t*)l_d)     = l_s->val.i32;   break;
       case nsXPTType::T_I64   : *((int64_t*)l_d)     = l_s->val.i64;   break;
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_sparcv9_solaris.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-
-/* Platform specific code to invoke XPCOM methods on native objects */
-
-#include "xptcprivate.h"
-
-#if !defined(__sparc) && !defined(__sparc__)
-#error "This code is for Sparc only"
-#endif
-
-/* Prototype specifies unmangled function name */
-extern "C" uint64_t
-invoke_copy_to_stack(uint64_t* d, uint32_t paramCount, nsXPTCVariant* s);
-
-extern "C" uint64_t
-invoke_copy_to_stack(uint64_t* d, uint32_t paramCount, nsXPTCVariant* s)
-{
-  /*
-    We need to copy the parameters for this function to locals and use them
-    from there since the parameters occupy the same stack space as the stack
-    we're trying to populate.
-  */
-  uint64_t *l_d = d;
-  nsXPTCVariant *l_s = s;
-  uint64_t l_paramCount = paramCount;
-  uint64_t regCount = 0;  // return the number of registers to load from the stack
-
-  for(uint64_t i = 0; i < l_paramCount; i++, l_d++, l_s++)
-  {
-    if (regCount < 5) regCount++;
-
-    if (l_s->IsPtrData())
-    {
-      *l_d = (uint64_t)l_s->ptr;
-      continue;
-    }
-    switch (l_s->type)
-    {
-      case nsXPTType::T_I8    : *((int64_t*)l_d)     = l_s->val.i8;    break;
-      case nsXPTType::T_I16   : *((int64_t*)l_d)     = l_s->val.i16;   break;
-      case nsXPTType::T_I32   : *((int64_t*)l_d)     = l_s->val.i32;   break;
-      case nsXPTType::T_I64   : *((int64_t*)l_d)     = l_s->val.i64;   break;
-
-      case nsXPTType::T_U8    : *((uint64_t*)l_d)    = l_s->val.u8;    break;
-      case nsXPTType::T_U16   : *((uint64_t*)l_d)    = l_s->val.u16;   break;
-      case nsXPTType::T_U32   : *((uint64_t*)l_d)    = l_s->val.u32;   break;
-      case nsXPTType::T_U64   : *((uint64_t*)l_d)    = l_s->val.u64;   break;
-
-      /* in the case of floats, we want to put the bits in to the
-         64bit space right justified... floats in the parameter array on
-         sparcv9 use odd numbered registers.. %f1, %f3, so we have to skip
-         the space that would be occupied by %f0, %f2, etc.
-      */
-      case nsXPTType::T_FLOAT : *(((float*)l_d) + 1) = l_s->val.f;     break;
-      case nsXPTType::T_DOUBLE: *((double*)l_d)      = l_s->val.d;     break;
-      case nsXPTType::T_BOOL  : *((uint64_t*)l_d)    = l_s->val.b;     break;
-      case nsXPTType::T_CHAR  : *((uint64_t*)l_d)    = l_s->val.c;     break;
-      case nsXPTType::T_WCHAR : *((int64_t*)l_d)     = l_s->val.wc;    break;
-
-      default:
-        // all the others are plain pointer types
-        *((void**)l_d) = l_s->val.p;
-        break;
-    }
-  }
-
-  return regCount;
-}
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_solaris.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-// Platform specific code to invoke XPCOM methods on native objects
-
-#include "xptcprivate.h"
-#include "alloca.h"
-
-// 6 integral parameters are passed in registers
-const uint32_t GPR_COUNT = 6;
-
-// 8 floating point parameters are passed in SSE registers
-const uint32_t FPR_COUNT = 8;
-
-// Remember that these 'words' are 64-bit long
-static inline void
-invoke_count_words(uint32_t paramCount, nsXPTCVariant * s,
-                   uint32_t & nr_gpr, uint32_t & nr_fpr, uint32_t & nr_stack)
-{
-    nr_gpr = 1; // skip one GP register for 'that'
-    nr_fpr = 0;
-    nr_stack = 0;
-
-    /* Compute number of eightbytes of class MEMORY.  */
-    for (uint32_t i = 0; i < paramCount; i++, s++) {
-        if (!s->IsPtrData()
-            && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) {
-            if (nr_fpr < FPR_COUNT)
-                nr_fpr++;
-            else
-                nr_stack++;
-        }
-        else {
-            if (nr_gpr < GPR_COUNT)
-                nr_gpr++;
-            else
-                nr_stack++;
-        }
-    }
-}
-
-static void
-invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s,
-                     uint64_t * gpregs, double * fpregs)
-{
-    uint32_t nr_gpr = 1; // skip one GP register for 'that'
-    uint32_t nr_fpr = 0;
-    uint64_t value;
-
-    for (uint32_t i = 0; i < paramCount; i++, s++) {
-        if (s->IsPtrData())
-            value = (uint64_t) s->ptr;
-        else {
-            switch (s->type) {
-            case nsXPTType::T_FLOAT:                                break;
-            case nsXPTType::T_DOUBLE:                               break;
-            case nsXPTType::T_I8:     value = s->val.i8;            break;
-            case nsXPTType::T_I16:    value = s->val.i16;           break;
-            case nsXPTType::T_I32:    value = s->val.i32;           break;
-            case nsXPTType::T_I64:    value = s->val.i64;           break;
-            case nsXPTType::T_U8:     value = s->val.u8;            break;
-            case nsXPTType::T_U16:    value = s->val.u16;           break;
-            case nsXPTType::T_U32:    value = s->val.u32;           break;
-            case nsXPTType::T_U64:    value = s->val.u64;           break;
-            case nsXPTType::T_BOOL:   value = s->val.b;             break;
-            case nsXPTType::T_CHAR:   value = s->val.c;             break;
-            case nsXPTType::T_WCHAR:  value = s->val.wc;            break;
-            default:                  value = (uint64_t) s->val.p;  break;
-            }
-        }
-
-        if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) {
-            if (nr_fpr < FPR_COUNT)
-                fpregs[nr_fpr++] = s->val.d;
-            else {
-                *((double *)d) = s->val.d;
-                d++;
-            }
-        }
-        else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) {
-            if (nr_fpr < FPR_COUNT)
-                // The value in %xmm register is already prepared to
-                // be retrieved as a float. Therefore, we pass the
-                // value verbatim, as a double without conversion.
-                fpregs[nr_fpr++] = s->val.d;
-            else {
-                *((float *)d) = s->val.f;
-                d++;
-            }
-        }
-        else {
-            if (nr_gpr < GPR_COUNT)
-                gpregs[nr_gpr++] = value;
-            else
-                *d++ = value;
-        }
-    }
-}
-
-// Avoid AddressSanitizer instrumentation for the next function because it
-// depends on __builtin_alloca behavior and alignment that cannot be relied on
-// once the function is compiled with a version of ASan that has dynamic-alloca
-// instrumentation enabled.
-
-MOZ_ASAN_BLACKLIST
-EXPORT_XPCOM_API(nsresult)
-NS_InvokeByIndex(nsISupports * that, uint32_t methodIndex,
-                 uint32_t paramCount, nsXPTCVariant * params)
-{
-    uint32_t nr_gpr, nr_fpr, nr_stack;
-    invoke_count_words(paramCount, params, nr_gpr, nr_fpr, nr_stack);
-
-    // Stack, if used, must be 16-bytes aligned
-    if (nr_stack)
-        nr_stack = (nr_stack + 1) & ~1;
-
-    // Load parameters to stack, if necessary
-    uint64_t *stack = (uint64_t *) __builtin_alloca(nr_stack * 8);
-    uint64_t gpregs[GPR_COUNT];
-    double fpregs[FPR_COUNT];
-    invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs);
-
-    switch (nr_fpr) {
-      case 8: asm("movupd %0, %xmm7" : : "xmm7" (fpregs[7]));
-      case 7: asm("movupd %0, %xmm6" : : "xmm6" (fpregs[6]));
-      case 6: asm("movupd %0, %xmm5" : : "xmm5" (fpregs[5]));
-      case 5: asm("movupd %0, %xmm4" : : "xmm4" (fpregs[4]));
-      case 4: asm("movupd %0, %xmm3" : : "xmm3" (fpregs[3]));
-      case 3: asm("movupd %0, %xmm2" : : "xmm2" (fpregs[2]));
-      case 2: asm("movupd %0, %xmm1" : : "xmm1" (fpregs[1]));
-      case 1: asm("movupd %0, %xmm0" : : "xmm0" (fpregs[0]));
-      case 0:;
-    }
-
-    // Ensure that assignments to SSE registers won't be optimized away
-    asm("" ::: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7");
-
-    // Get pointer to method
-    uint64_t methodAddress = *((uint64_t *)that);
-    methodAddress += 16 + 8 * methodIndex;
-    methodAddress = *((uint64_t *)methodAddress);
-
-    typedef uint32_t (*Method)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
-    uint32_t result = ((Method)methodAddress)((uint64_t)that, gpregs[1], gpregs[2], gpregs[3], gpregs[4], gpregs[5]);
-    return result;
-}
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_solaris.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-/* Platform specific code to invoke XPCOM methods on native objects */
-
-#include "xptcprivate.h"
-
-extern "C" {
-
-// Remember that these 'words' are 32bit DWORDS
-
-uint32_t
-invoke_count_words(uint32_t paramCount, nsXPTCVariant* s)
-{
-    uint32_t result = 0;
-    for(uint32_t i = 0; i < paramCount; i++, s++)
-    {
-        if(s->IsPtrData())
-        {
-            result++;
-            continue;
-        }
-        result++;
-        switch(s->type)
-        {
-        case nsXPTType::T_I64    :
-        case nsXPTType::T_U64    :
-        case nsXPTType::T_DOUBLE :
-            result++;
-            break;
-        default:
-            break;
-        }
-    }
-    return result;
-}
-
-void
-invoke_copy_to_stack(uint32_t paramCount, nsXPTCVariant* s, uint32_t* d)
-{
-    for(uint32_t i = 0; i < paramCount; i++, d++, s++)
-    {
-        if(s->IsPtrData())
-        {
-            *((void**)d) = s->ptr;
-            continue;
-        }
-
-/* XXX: the following line is here (rather than as the default clause in
- *      the following switch statement) so that the Sun native compiler
- *      will generate the correct assembly code on the Solaris Intel
- *      platform. See the comments in bug #28817 for more details.
- */
-
-        *((void**)d) = s->val.p;
-
-        switch(s->type)
-        {
-        case nsXPTType::T_I64    : *((int64_t*) d) = s->val.i64; d++;    break;
-        case nsXPTType::T_U64    : *((uint64_t*)d) = s->val.u64; d++;    break;
-        case nsXPTType::T_DOUBLE : *((double*)  d) = s->val.d;   d++;    break;
-        default                  : break;
-        }
-    }
-}
-
-}
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcstubs_asm_sparcv9_solaris.s
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: asm; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-        .global SharedStub
-
-/*
-    in the frame for the function that called SharedStub are the
-    rest of the parameters we need
-
-*/
-
-SharedStub:
-! we don't create a new frame yet, but work within the frame of the calling
-! function to give ourselves the other parameters we want
-
-        mov     %o0, %o1               ! shuffle the index up to 2nd place
-        mov     %i0, %o0               ! the original 'this'
-        add     %fp, 0x7ff + 136, %o2  ! previous stack top adjusted to the first argument slot (beyond 'this')
-
-! save off the original incoming parameters that arrived in 
-! registers, the ABI guarantees the space for us to do this
-        stx     %i1, [%fp + 0x7ff + 136]
-        stx     %i2, [%fp + 0x7ff + 144]
-        stx     %i3, [%fp + 0x7ff + 152]
-        stx     %i4, [%fp + 0x7ff + 160]
-        stx     %i5, [%fp + 0x7ff + 168]
-! now we can build our own stack frame
-        save    %sp,-(128 + 64),%sp    ! room for the register window and
-                                       ! struct pointer, rounded up to 0 % 64
-! our function now appears to have been called
-! as SharedStub(nsISupports* that, uint32_t index, uint32_t* args)
-! so we can just copy these through
-
-        mov     %i0, %o0
-        mov     %i1, %o1
-        mov     %i2, %o2
-        call    PrepareAndDispatch
-        nop
-        mov     %o0,%i0             ! propagate return value
-        b .LL1
-        nop
-.LL1:
-        ret
-        restore
-
-       .size    SharedStub, .-SharedStub
-       .type    SharedStub, #function
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcstubs_asm_x86_64_solaris_SUNW.s
+++ /dev/null
@@ -1,63 +0,0 @@
-#define STUB_ENTRY1(nn) \
-    .globl	__1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_; \
-    .hidden	__1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_; \
-    .type	__1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_, @function; \
-__1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_: \
-    movl	$/**/nn/**/, %eax; \
-    jmp	SharedStub; \
-    .size	__1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_, . - __1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_ \
-
-#define STUB_ENTRY2(nn) \
-    .globl	__1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_; \
-    .hidden	__1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_; \
-    .type	__1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_, @function; \
-__1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_: \
-    movl	$/**/nn/**/, %eax; \
-    jmp	SharedStub; \
-    .size	__1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_, . - __1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_ \
-
-#define STUB_ENTRY3(nn) \
-    .globl	__1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_; \
-    .hidden	__1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_; \
-    .type	__1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_, @function; \
-__1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_: \
-    movl	$/**/nn/**/, %eax; \
-    jmp	SharedStub; \
-    .size	__1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_, . - __1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_ \
-
-// static nsresult SharedStub(uint32_t methodIndex)
-    .type      SharedStub, @function;
-    SharedStub:
-    // make room for gpregs (48), fpregs (64)
-    pushq      %rbp;
-    movq       %rsp,%rbp;
-    subq       $112,%rsp;
-    // save GP registers
-    movq       %rdi,-112(%rbp);
-    movq       %rsi,-104(%rbp);
-    movq       %rdx, -96(%rbp);
-    movq       %rcx, -88(%rbp);
-    movq       %r8 , -80(%rbp);
-    movq       %r9 , -72(%rbp);
-    leaq       -112(%rbp),%rcx;
-    // save FP registers
-    movsd      %xmm0,-64(%rbp);
-    movsd      %xmm1,-56(%rbp);
-    movsd      %xmm2,-48(%rbp);
-    movsd      %xmm3,-40(%rbp);
-    movsd      %xmm4,-32(%rbp);
-    movsd      %xmm5,-24(%rbp);
-    movsd      %xmm6,-16(%rbp);
-    movsd      %xmm7, -8(%rbp);
-    leaq       -64(%rbp),%r8;
-    // rdi has the 'self' pointer already
-    movl       %eax,%esi;
-    leaq       16(%rbp),%rdx;
-    call       PrepareAndDispatch@plt;
-    leave;
-    ret;
-    .size      SharedStub, . - SharedStub
-
-#define SENTINEL_ENTRY(nn)
-
-#include "xptcstubsdef_asm.solx86"
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcstubs_asm_x86_solaris_SUNW.s
+++ /dev/null
@@ -1,78 +0,0 @@
-#define STUB_ENTRY1(nn)	\
- 	.globl __1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_; \
-	.type __1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_, @function; \
-__1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_: \
-	push       %ebp; \
-	movl       %esp,%ebp; \
-	andl       $-16,%esp; \
-	push       %ebx;	\
-	call       .CG4./**/nn/**/; \
-.CG4./**/nn/**/: \
-	pop        %ebx;	 \
-	addl       $_GLOBAL_OFFSET_TABLE_+0x1,%ebx; \
-	leal	0xc(%ebp), %ecx; \
-	pushl	%ecx; \
-	pushl	$/**/nn/**/; \
-	movl	0x8(%ebp), %ecx; \
-	pushl	%ecx; \
-	call	__1cSPrepareAndDispatch6FpnOnsXPTCStubBase_IpI_I_; \
-	addl	$0xc , %esp; \
-	pop        %ebx; \
-	movl       %ebp,%esp; \
-	pop        %ebp; \
-	ret        ; \
-	.size __1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_, . - __1cOnsXPTCStubBaseFStub/**/nn/**/6M_I_ \
-
-#define STUB_ENTRY2(nn)	\
- 	.globl __1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_; \
-	.type __1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_, @function; \
-__1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_: \
-	push       %ebp; \
-	movl       %esp,%ebp; \
-	andl       $-16,%esp; \
-	push       %ebx;	\
-	call       .CG4./**/nn/**/; \
-.CG4./**/nn/**/: \
-	pop        %ebx;	 \
-	addl       $_GLOBAL_OFFSET_TABLE_+0x1,%ebx; \
-	leal	0xc(%ebp), %ecx; \
-	pushl	%ecx; \
-	pushl	$/**/nn/**/; \
-	movl	0x8(%ebp), %ecx; \
-	pushl	%ecx; \
-	call	__1cSPrepareAndDispatch6FpnOnsXPTCStubBase_IpI_I_; \
-	addl	$0xc , %esp; \
-	pop        %ebx; \
-	movl       %ebp,%esp; \
-	pop        %ebp; \
-	ret        ; \
-	.size __1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_, . - __1cOnsXPTCStubBaseGStub/**/nn/**/6M_I_ \
-
-#define STUB_ENTRY3(nn)	\
- 	.globl __1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_; \
-	.type __1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_, @function; \
-__1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_: \
-	push       %ebp; \
-	movl       %esp,%ebp; \
-	andl       $-16,%esp; \
-	push       %ebx;	\
-	call       .CG4./**/nn/**/; \
-.CG4./**/nn/**/: \
-	pop        %ebx;	 \
-	addl       $_GLOBAL_OFFSET_TABLE_+0x1,%ebx; \
-	leal	0xc(%ebp), %ecx; \
-	pushl	%ecx; \
-	pushl	$/**/nn/**/; \
-	movl	0x8(%ebp), %ecx; \
-	pushl	%ecx; \
-	call	__1cSPrepareAndDispatch6FpnOnsXPTCStubBase_IpI_I_; \
-	addl	$0xc , %esp; \
-	pop        %ebx; \
-	movl       %ebp,%esp; \
-	pop        %ebp; \
-	ret        ; \
-	.size __1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_, . - __1cOnsXPTCStubBaseHStub/**/nn/**/6M_I_ \
-
-#define SENTINEL_ENTRY(nn)
-
-#include "xptcstubsdef_asm.solx86"
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcstubs_sparcv9_solaris.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* Implement shared vtbl methods. */
-
-#include "xptcprivate.h"
-
-#if defined(sparc) || defined(__sparc__)
-
-extern "C" nsresult ATTRIBUTE_USED
-PrepareAndDispatch(nsXPTCStubBase* self, uint64_t methodIndex, uint64_t* args)
-{
-
-#define PARAM_BUFFER_COUNT     16
-
-    nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
-    nsXPTCMiniVariant* dispatchParams = nullptr;
-    const nsXPTMethodInfo* info;
-    uint8_t paramCount;
-    uint8_t i;
-
-    NS_ASSERTION(self,"no self");
-
-    self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info);
-    NS_ASSERTION(info,"no interface info");
-
-    paramCount = info->GetParamCount();
-
-    // setup variant array pointer
-    if(paramCount > PARAM_BUFFER_COUNT)
-        dispatchParams = new nsXPTCMiniVariant[paramCount];
-    else
-        dispatchParams = paramBuffer;
-    NS_ASSERTION(dispatchParams,"no place for params");
-
-    const uint8_t indexOfJSContext = info->IndexOfJSContext();
-
-    uint64_t* ap = args;
-    for(i = 0; i < paramCount; i++, ap++)
-    {
-        const nsXPTParamInfo& param = info->GetParam(i);
-        const nsXPTType& type = param.GetType();
-        nsXPTCMiniVariant* dp = &dispatchParams[i];
-
-        if (i == indexOfJSContext)
-            ap++;
-
-        if(param.IsOut() || !type.IsArithmetic())
-        {
-            dp->val.p = (void*) *ap;
-            continue;
-        }
-        // else
-        switch(type)
-        {
-        case nsXPTType::T_I8     : dp->val.i8  = *((int64_t*) ap);       break;
-        case nsXPTType::T_I16    : dp->val.i16 = *((int64_t*) ap);       break;
-        case nsXPTType::T_I32    : dp->val.i32 = *((int64_t*) ap);       break;
-        case nsXPTType::T_DOUBLE : dp->val.d   = *((double*)  ap);       break;
-        case nsXPTType::T_U64    : dp->val.u64 = *((uint64_t*)ap);       break;
-        case nsXPTType::T_I64    : dp->val.i64 = *((int64_t*) ap);       break;
-        case nsXPTType::T_U8     : dp->val.u8  = *((uint64_t*)ap);       break;
-        case nsXPTType::T_U16    : dp->val.u16 = *((uint64_t*)ap);       break;
-        case nsXPTType::T_U32    : dp->val.u32 = *((uint64_t*)ap);       break;
-        case nsXPTType::T_FLOAT  : dp->val.f   =  ((float*)   ap)[1];    break;
-        case nsXPTType::T_BOOL   : dp->val.b   = *((uint64_t*)ap);       break;
-        case nsXPTType::T_CHAR   : dp->val.c   = *((uint64_t*)ap);       break;
-        case nsXPTType::T_WCHAR  : dp->val.wc  = *((int64_t*) ap);       break;
-        default:
-            NS_ERROR("bad type");
-            break;
-        }
-    }
-
-    nsresult result = self->mOuter->CallMethod((uint16_t)methodIndex, info,
-                                               dispatchParams);
-
-    if(dispatchParams != paramBuffer)
-        delete [] dispatchParams;
-
-    return result;
-}
-
-extern "C" nsresult SharedStub(int, int*);
-
-#define STUB_ENTRY(n) \
-nsresult nsXPTCStubBase::Stub##n() \
-{ \
-	int dummy; /* defeat tail-call optimization */ \
-	return SharedStub(n, &dummy); \
-}
-
-#define SENTINEL_ENTRY(n) \
-nsresult nsXPTCStubBase::Sentinel##n() \
-{ \
-    NS_ERROR("nsXPTCStubBase::Sentinel called"); \
-    return NS_ERROR_NOT_IMPLEMENTED; \
-}
-
-#include "xptcstubsdef.inc"
-
-#endif /* sparc || __sparc__ */
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcstubs_x86_64_solaris.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-// Implement shared vtbl methods.
-
-// Keep this in sync with the darwin version.
-
-#include "xptcprivate.h"
-
-// The Linux/x86-64 ABI passes the first 6 integer parameters and the
-// first 8 floating point parameters in registers (rdi, rsi, rdx, rcx,
-// r8, r9 and xmm0-xmm7), no stack space is allocated for these by the
-// caller.  The rest of the parameters are passed in the callers stack
-// area.
-
-const uint32_t PARAM_BUFFER_COUNT   = 16;
-const uint32_t GPR_COUNT            = 6;
-const uint32_t FPR_COUNT            = 8;
-
-// PrepareAndDispatch() is called by SharedStub() and calls the actual method.
-//
-// - 'args[]' contains the arguments passed on stack
-// - 'gpregs[]' contains the arguments passed in integer registers
-// - 'fpregs[]' contains the arguments passed in floating point registers
-//
-// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
-// and then the method gets called.
-
-extern "C" nsresult ATTRIBUTE_USED
-PrepareAndDispatch(nsXPTCStubBase * self, uint32_t methodIndex,
-                   uint64_t * args, uint64_t * gpregs, double *fpregs)
-{
-    nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
-    nsXPTCMiniVariant* dispatchParams = nullptr;
-    const nsXPTMethodInfo* info;
-    uint32_t paramCount;
-    uint32_t i;
-
-    NS_ASSERTION(self,"no self");
-
-    self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info);
-    NS_ASSERTION(info,"no method info");
-    if (!info)
-        return NS_ERROR_UNEXPECTED;
-
-    paramCount = info->GetParamCount();
-
-    // setup variant array pointer
-    if (paramCount > PARAM_BUFFER_COUNT)
-        dispatchParams = new nsXPTCMiniVariant[paramCount];
-    else
-        dispatchParams = paramBuffer;
-
-    NS_ASSERTION(dispatchParams,"no place for params");
-    if (!dispatchParams)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    const uint8_t indexOfJSContext = info->IndexOfJSContext();
-
-    uint64_t* ap = args;
-    uint32_t nr_gpr = 1;    // skip one GPR register for 'that'
-    uint32_t nr_fpr = 0;
-    uint64_t value;
-
-    for (i = 0; i < paramCount; i++) {
-        const nsXPTParamInfo& param = info->GetParam(i);
-        const nsXPTType& type = param.GetType();
-        nsXPTCMiniVariant* dp = &dispatchParams[i];
-
-        if (i == indexOfJSContext) {
-            if (nr_gpr < GPR_COUNT)
-                nr_gpr++;
-            else
-                ap++;
-        }
-
-        if (!param.IsOut() && type == nsXPTType::T_DOUBLE) {
-            if (nr_fpr < FPR_COUNT)
-                dp->val.d = fpregs[nr_fpr++];
-            else
-                dp->val.d = *(double*) ap++;
-            continue;
-        }
-        else if (!param.IsOut() && type == nsXPTType::T_FLOAT) {
-            if (nr_fpr < FPR_COUNT)
-                // The value in %xmm register is already prepared to
-                // be retrieved as a float. Therefore, we pass the
-                // value verbatim, as a double without conversion.
-                dp->val.d = fpregs[nr_fpr++];
-            else
-                dp->val.f = *(float*) ap++;
-            continue;
-        }
-        else {
-            if (nr_gpr < GPR_COUNT)
-                value = gpregs[nr_gpr++];
-            else
-                value = *ap++;
-        }
-
-        if (param.IsOut() || !type.IsArithmetic()) {
-            dp->val.p = (void*) value;
-            continue;
-        }
-
-        switch (type) {
-        case nsXPTType::T_I8:      dp->val.i8  = (int8_t)   value; break;
-        case nsXPTType::T_I16:     dp->val.i16 = (int16_t)  value; break;
-        case nsXPTType::T_I32:     dp->val.i32 = (int32_t)  value; break;
-        case nsXPTType::T_I64:     dp->val.i64 = (int64_t)  value; break;
-        case nsXPTType::T_U8:      dp->val.u8  = (uint8_t)  value; break;
-        case nsXPTType::T_U16:     dp->val.u16 = (uint16_t) value; break;
-        case nsXPTType::T_U32:     dp->val.u32 = (uint32_t) value; break;
-        case nsXPTType::T_U64:     dp->val.u64 = (uint64_t) value; break;
-        // Cast to uint8_t first, to remove garbage on upper 56 bits.
-        case nsXPTType::T_BOOL:    dp->val.b   = (bool)(uint8_t)   value; break;
-        case nsXPTType::T_CHAR:    dp->val.c   = (char)     value; break;
-        case nsXPTType::T_WCHAR:   dp->val.wc  = (wchar_t)  value; break;
-
-        default:
-            NS_ERROR("bad type");
-            break;
-        }
-    }
-
-    nsresult result = self->mOuter->CallMethod((uint16_t) methodIndex, info,
-                                               dispatchParams);
-
-    if (dispatchParams != paramBuffer)
-        delete [] dispatchParams;
-
-    return result;
-}
-
-#define STUB_ENTRY(n)
-
-#define SENTINEL_ENTRY(n) \
-nsresult nsXPTCStubBase::Sentinel##n() \
-{ \
-    NS_ERROR("nsXPTCStubBase::Sentinel called"); \
-    return NS_ERROR_NOT_IMPLEMENTED; \
-}
-
-#include "xptcstubsdef.inc"
deleted file mode 100644
--- a/xpcom/reflect/xptcall/md/unix/xptcstubs_x86_solaris.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-/* Implement shared vtbl methods. */
-
-#include "xptcprivate.h"
-
-nsresult ATTRIBUTE_USED
-PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
-{
-#define PARAM_BUFFER_COUNT     16
-
-    nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
-    nsXPTCMiniVariant* dispatchParams = nullptr;
-    const nsXPTMethodInfo* info;
-    uint8_t paramCount;
-    uint8_t i;
-
-    NS_ASSERTION(self,"no self");
-
-    self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info);
-    NS_ASSERTION(info,"no interface info");
-
-    paramCount = info->GetParamCount();
-
-    // setup variant array pointer
-    if(paramCount > PARAM_BUFFER_COUNT)
-        dispatchParams = new nsXPTCMiniVariant[paramCount];
-    else
-        dispatchParams = paramBuffer;
-    NS_ASSERTION(dispatchParams,"no place for params");
-
-    const uint8_t indexOfJSContext = info->IndexOfJSContext();
-
-    uint32_t* ap = args;
-    for(i = 0; i < paramCount; i++, ap++)
-    {
-        const nsXPTParamInfo& param = info->GetParam(i);
-        const nsXPTType& type = param.GetType();
-        nsXPTCMiniVariant* dp = &dispatchParams[i];
-
-        if (i == indexOfJSContext)
-            ap++;
-
-        if(param.IsOut() || !type.IsArithmetic())
-        {
-            dp->val.p = (void*) *ap;
-            continue;
-        }
-        // else
-	    dp->val.p = (void*) *ap;
-        switch(type)
-        {
-        case nsXPTType::T_I64    : dp->val.i64 = *((int64_t*) ap); ap++; break;
-        case nsXPTType::T_U64    : dp->val.u64 = *((uint64_t*)ap); ap++; break;
-        case nsXPTType::T_DOUBLE : dp->val.d   = *((double*)  ap); ap++; break;
-        default                  : break;
-        }
-    }
-
-    nsresult result = self->mOuter->CallMethod((uint16_t)methodIndex, info,
-                                               dispatchParams);
-
-    if(dispatchParams != paramBuffer)
-        delete [] dispatchParams;
-
-    return result;
-}
-
-#define STUB_ENTRY(n)
-
-#define SENTINEL_ENTRY(n) \
-nsresult nsXPTCStubBase::Sentinel##n() \
-{ \
-    NS_ERROR("nsXPTCStubBase::Sentinel called"); \
-    return NS_ERROR_NOT_IMPLEMENTED; \
-}
-
-#include "xptcstubsdef.inc"