merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 19 Jan 2017 16:05:22 +0100
changeset 377391 a3978751f45108ff1ae002ecebdc0fa23fc52b84
parent 377315 168ea3e9ff0bad286676173263613703187ab8f1 (current diff)
parent 377390 3112cbcca0f41c1fff13a287d71a61267111edbb (diff)
child 377435 552e15caf7384fbf025dc940267c137f77692b47
child 377466 2eee285e14df884fa6dc346ec5d414400751d7dd
child 391116 514c46f975dd5c48ad23a8a10c54026253e15fdb
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
first release with
nightly linux32
a3978751f451 / 53.0a1 / 20170119222621 / files
nightly linux64
a3978751f451 / 53.0a1 / 20170119222621 / files
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
merge mozilla-inbound to mozilla-central a=merge
browser/components/extensions/ext-utils.js
dom/media/MediaDecoder.cpp
dom/media/gmp/GMPChild.cpp
layout/style/nsStyleStruct.cpp
security/nss/fuzz/nssfuzz.cc
security/nss/fuzz/quickder_targets.cc
security/nss/fuzz/registry.h
security/nss/gtests/common/common.gyp
security/nss/lib/freebl/ecl/tests/ec_naft.c
security/nss/lib/freebl/ecl/tests/ecp_test.c
security/nss/lib/freebl/os2_rand.c
tools/profiler/core/IntelPowerGadget.cpp
tools/profiler/core/IntelPowerGadget.h
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -369,62 +369,62 @@ DocAccessibleParent::RecvRoleChangedEven
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
 {
   // One document should never directly be the child of another.
   // We should always have at least an outer doc accessible in between.
   MOZ_ASSERT(aID);
   if (!aID)
-    return IPC_FAIL_NO_REASON(this);
+    return IPC_FAIL(this, "ID is 0!");
 
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
 
   auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc);
   childDoc->Unbind();
-  bool result = AddChildDoc(childDoc, aID, false);
+  ipc::IPCResult result = AddChildDoc(childDoc, aID, false);
   MOZ_ASSERT(result);
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
   if (!result) {
-    return IPC_FAIL_NO_REASON(this);
+    return result;
   }
   return IPC_OK();
 }
 
-bool
+ipc::IPCResult
 DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
                                  uint64_t aParentID, bool aCreating)
 {
   // We do not use GetAccessible here because we want to be sure to not get the
   // document it self.
   ProxyEntry* e = mAccessibles.GetEntry(aParentID);
   if (!e)
-    return false;
+    return IPC_FAIL(this, "binding to nonexistant proxy!");
 
   ProxyAccessible* outerDoc = e->mProxy;
   MOZ_ASSERT(outerDoc);
 
   // OuterDocAccessibles are expected to only have a document as a child.
   // However for compatibility we tolerate replacing one document with another
   // here.
   if (outerDoc->ChildrenCount() > 1 ||
       (outerDoc->ChildrenCount() == 1 && !outerDoc->ChildAt(0)->IsDoc())) {
-    return false;
+    return IPC_FAIL(this, "binding to proxy that can't be a outerDoc!");
   }
 
   aChildDoc->mParent = outerDoc;
   outerDoc->SetChildDoc(aChildDoc);
   mChildDocs.AppendElement(aChildDoc);
   aChildDoc->mParentDoc = this;
 
   if (aCreating) {
     ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
   }
 
-  return true;
+  return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvShutdown()
 {
   Destroy();
 
   auto mgr = static_cast<dom::TabParent*>(Manager());
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -97,18 +97,18 @@ public:
    * of the document this object represents.
    */
   DocAccessibleParent* ParentDoc() const { return mParentDoc; }
 
   /*
    * Called when a document in a content process notifies the main process of a
    * new child document.
    */
-  bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID,
-                   bool aCreating = true);
+  ipc::IPCResult AddChildDoc(DocAccessibleParent* aChildDoc,
+                             uint64_t aParentID, bool aCreating = true);
 
   /*
    * Called when the document in the content process this object represents
    * notifies the main process a child document has been removed.
    */
   void RemoveChildDoc(DocAccessibleParent* aChildDoc)
   {
     aChildDoc->Parent()->ClearChildDoc(aChildDoc);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1019,16 +1019,27 @@ pref("security.sandbox.content.level", 2
 #if defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
 // ID (a UUID when set by gecko) that is used to form the name of a
 // sandbox-writable temporary directory to be used by content processes
 // when a temporary writable file is required in a level 1 sandbox.
 pref("security.sandbox.content.tempDirSuffix", "");
 #endif
 #endif
 
+#if defined(MOZ_SANDBOX)
+#if defined(XP_MACOSX)
+// This pref determines if messages relevant to sandbox violations are
+// logged.
+// At present, this setting refers only to mac sandbox messages sent to
+// the system console but the setting will be used on other platforms
+// in the future.
+pref("security.sandbox.logging.enabled", true);
+#endif
+#endif
+
 // This pref governs whether we attempt to work around problems caused by
 // plugins using OS calls to manipulate the cursor while running out-of-
 // process.  These workarounds all involve intercepting (hooking) certain
 // OS calls in the plugin process, then arranging to make certain OS calls
 // in the browser process.  Eventually plugins will be required to use the
 // NPAPI to manipulate the cursor, and these workarounds will be removed.
 // See bug 621117.
 #ifdef XP_MACOSX
--- a/browser/base/content/blockedSite.xhtml
+++ b/browser/base/content/blockedSite.xhtml
@@ -130,17 +130,17 @@
         if (!getOverride()) {
           var btn = document.getElementById("ignoreWarningButton");
           if (btn) {
             btn.parentNode.removeChild(btn);
           }
         }
 
         // Inform the test harness that we're done loading the page
-        var event = new CustomEvent("AboutBlockedLoaded");
+        var event = new CustomEvent("AboutBlockedLoaded", {bubbles:true});
         document.dispatchEvent(event);
       }
     ]]></script>
   </head>
 
   <body dir="&locale.dir;">
     <div id="errorPageContainer" class="container">
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -7033,16 +7033,20 @@
       <method name="_mouseenter">
         <body><![CDATA[
           if (this.hidden || this.closing)
             return;
 
           let tabContainer = this.parentNode;
           let visibleTabs = tabContainer.tabbrowser.visibleTabs;
           let tabIndex = visibleTabs.indexOf(this);
+
+          if (this.selected)
+            tabContainer._handleTabSelect();
+
           if (tabIndex == 0) {
             tabContainer._beforeHoveredTab = null;
           } else {
             let candidate = visibleTabs[tabIndex - 1];
             if (!candidate.selected) {
               tabContainer._beforeHoveredTab = candidate;
               candidate.setAttribute("beforehovered", "true");
             }
index de43b24888b2ed82f526c6af1455ef8288d0ed52..e9402bde6b01c1de759644a8971cf3d3a51d4681
GIT binary patch
literal 16579
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
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -1,14 +1,16 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
                                   "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
                                   "resource://gre/modules/Timer.jsm");
@@ -228,16 +230,17 @@ class BasePopup {
     browser.setAttribute("disableglobalhistory", "true");
     browser.setAttribute("transparent", "true");
     browser.setAttribute("class", "webextension-popup-browser");
     browser.setAttribute("webextension-view-type", "popup");
     browser.setAttribute("tooltip", "aHTMLTooltip");
 
     if (this.extension.remote) {
       browser.setAttribute("remote", "true");
+      browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
     }
 
     // We only need flex sizing for the sake of the slide-in sub-views of the
     // main menu panel, so that the browser occupies the full width of the view,
     // and also takes up any extra height that's available to it.
     browser.setAttribute("flex", "1");
 
     // Note: When using noautohide panels, the popup manager will add width and
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -21,19 +21,22 @@ const {AppConstants} = Cu.import("resour
 const {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", {});
 
 // We run tests under two different configurations, from browser.ini and
 // browser-remote.ini. When running from browser-remote.ini, the tests are
 // copied to the sub-directory "test-oop-extensions", which we detect here, and
 // use to select our configuration.
 if (gTestPath.includes("test-oop-extensions")) {
   SpecialPowers.pushPrefEnv({set: [
-    ["dom.ipc.processCount", 1],
+    ["dom.ipc.processCount.extension", 1],
     ["extensions.webextensions.remote", true],
   ]});
+  // We don't want to reset this at the end of the test, so that we don't have
+  // to spawn a new extension child process for each test unit.
+  SpecialPowers.setIntPref("dom.ipc.keepProcessesAlive.extension", 1);
 }
 
 // Bug 1239884: Our tests occasionally hit a long GC pause at unpredictable
 // times in debug builds, which results in intermittent timeouts. Until we have
 // a better solution, we force a GC after certain strategic tests, which tend to
 // accumulate a high number of unreaped windows.
 function forceGC() {
   if (AppConstants.DEBUG) {
--- a/browser/components/safebrowsing/content/test/browser.ini
+++ b/browser/components/safebrowsing/content/test/browser.ini
@@ -1,8 +1,11 @@
 [DEFAULT]
-support-files = head.js
+support-files =
+  head.js
+  empty_file.html
 
 [browser_bug400731.js]
 [browser_bug415846.js]
 # Disabled on Mac because of its bizarre special-and-unique snowflake of a help menu.
 skip-if = os == "mac" || e10s # e10s: Bug 1248632
 [browser_whitelisted.js]
+[browser_mixedcontent_aboutblocked.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { classes: Cc, interfaces: Ci, results: Cr } = Components;
+
+// This url must sync with the table, url in SafeBrowsing.jsm addMozEntries
+const PHISH_TABLE = "test-phish-simple";
+const PHISH_URL = "https://www.itisatrap.org/firefox/its-a-trap.html";
+
+const SECURE_CONTAINER_URL = "https://example.com/browser/browser/components/safebrowsing/content/test/empty_file.html";
+
+// This function is mostly ported from classifierCommon.js
+// under toolkit/components/url-classifier/tests/mochitest.
+function waitForDBInit(callback) {
+  // Since there are two cases that may trigger the callback,
+  // we have to carefully avoid multiple callbacks and observer
+  // leaking.
+  let didCallback = false;
+  function callbackOnce() {
+    Services.obs.removeObserver(obsFunc, "mozentries-update-finished");
+    if (!didCallback) {
+      callback();
+    }
+    didCallback = true;
+  }
+
+  // The first part: listen to internal event.
+  function obsFunc() {
+    ok(true, "Received internal event!");
+    callbackOnce();
+  }
+  Services.obs.addObserver(obsFunc, "mozentries-update-finished", false);
+
+  // The second part: we might have missed the event. Just do
+  // an internal database lookup to confirm if the url has been
+  // added.
+  let principal = Services.scriptSecurityManager
+    .createCodebasePrincipal(Services.io.newURI(PHISH_URL), {});
+
+  let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
+    .getService(Ci.nsIUrlClassifierDBService);
+  dbService.lookup(principal, PHISH_TABLE, value => {
+    if (value === PHISH_TABLE) {
+      ok(true, "DB lookup success!");
+      callbackOnce();
+    }
+  });
+}
+
+add_task(function* testNormalBrowsing() {
+  yield BrowserTestUtils.withNewTab(SECURE_CONTAINER_URL, function* (browser) {
+    // Before we load the phish url, we have to make sure the hard-coded
+    // black list has been added to the database.
+    yield new Promise(resolve => waitForDBInit(resolve));
+
+    yield ContentTask.spawn(browser, PHISH_URL, function* (aPhishUrl) {
+      return new Promise(resolve => {
+        // Register listener before loading phish URL.
+        let listener = e => {
+          removeEventListener("AboutBlockedLoaded", listener, false, true);
+          resolve();
+        };
+        addEventListener("AboutBlockedLoaded", listener, false, true);
+
+        // Create an iframe which is going to load a phish url.
+        let iframe = content.document.createElement("iframe");
+        iframe.src = aPhishUrl;
+        content.document.body.appendChild(iframe);
+      });
+    });
+
+    ok(true, "about:blocked is successfully loaded!");
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/safebrowsing/content/test/empty_file.html
@@ -0,0 +1,1 @@
+<html><body></body></html>
\ No newline at end of file
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -29,28 +29,30 @@ function getAboutModule(aURL) {
   }
 }
 
 const NOT_REMOTE = null;
 
 // These must match any similar ones in ContentParent.h.
 const WEB_REMOTE_TYPE = "web";
 const FILE_REMOTE_TYPE = "file";
+const EXTENSION_REMOTE_TYPE = "extension";
 const DEFAULT_REMOTE_TYPE = WEB_REMOTE_TYPE;
 
 function validatedWebRemoteType(aPreferredRemoteType) {
   return aPreferredRemoteType && aPreferredRemoteType.startsWith(WEB_REMOTE_TYPE)
          ? aPreferredRemoteType : WEB_REMOTE_TYPE;
 }
 
 this.E10SUtils = {
   DEFAULT_REMOTE_TYPE,
   NOT_REMOTE,
   WEB_REMOTE_TYPE,
   FILE_REMOTE_TYPE,
+  EXTENSION_REMOTE_TYPE,
 
   canLoadURIInProcess(aURL, aProcess) {
     let remoteType = aProcess == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT
                      ? DEFAULT_REMOTE_TYPE : NOT_REMOTE;
     return remoteType == this.getRemoteTypeForURI(aURL, true, remoteType);
   },
 
   getRemoteTypeForURI(aURL, aMultiProcess,
@@ -128,17 +130,17 @@ this.E10SUtils = {
           aPreferredRemoteType != NOT_REMOTE) {
         return DEFAULT_REMOTE_TYPE;
       }
 
       return NOT_REMOTE;
     }
 
     if (aURL.startsWith("moz-extension:")) {
-      return useRemoteWebExtensions ? WEB_REMOTE_TYPE : NOT_REMOTE;
+      return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
     }
 
     if (aURL.startsWith("view-source:")) {
       return this.getRemoteTypeForURI(aURL.substr("view-source:".length),
                                       aMultiProcess, aPreferredRemoteType);
     }
 
     return validatedWebRemoteType(aPreferredRemoteType);
--- a/build/build-clang/README
+++ b/build/build-clang/README
@@ -51,9 +51,8 @@ build-clang.py accepts a JSON config for
 
 Environment Variables
 ---------------------
 
 The following environment variables are used for cross-compile builds targeting OS X on Linux.
 
 * CROSS_CCTOOLS_PATH: Path to the cctools directory where the cross compiler toolchain is located.
 * CROSS_SYSROOT: Path to the OS X SDK directory for cross compile builds.
-* LIBCXX_INCLUDE_PATH: Path to the cross compiler libc++ headers.
--- a/build/build-clang/build-clang.py
+++ b/build/build-clang/build-clang.py
@@ -198,17 +198,17 @@ def is_linux():
 
 def is_windows():
     return platform.system() == "Windows"
 
 
 def build_one_stage(cc, cxx, ld, ar, ranlib,
                     src_dir, stage_dir, build_libcxx,
                     osx_cross_compile, build_type, assertions,
-                    python_path, gcc_dir):
+                    python_path, gcc_dir, libcxx_include_dir):
     if not os.path.exists(stage_dir):
         os.mkdir(stage_dir)
 
     build_dir = stage_dir + "/build"
     inst_dir = stage_dir + "/clang"
 
     # If CMake has already been run, it may have been run with different
     # arguments, so we need to re-run it.  Make sure the cached copy of the
@@ -244,17 +244,17 @@ def build_one_stage(cc, cxx, ld, ar, ran
         cmake_args.insert(-1, "-DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON")
         cmake_args.insert(-1, "-DLLVM_USE_CRT_RELEASE=MT")
     if ranlib is not None:
         cmake_args += ["-DCMAKE_RANLIB=%s" % slashify_path(ranlib)]
     if osx_cross_compile:
         cmake_args += ["-DCMAKE_SYSTEM_NAME=Darwin",
                        "-DCMAKE_SYSTEM_VERSION=10.10",
                        "-DLLVM_ENABLE_THREADS=OFF",
-                       "-DLIBCXXABI_LIBCXX_INCLUDES=%s" % slashify_path(os.getenv("LIBCXX_INCLUDE_PATH")),
+                       "-DLIBCXXABI_LIBCXX_INCLUDES=%s" % libcxx_include_dir,
                        "-DCMAKE_OSX_SYSROOT=%s" % slashify_path(os.getenv("CROSS_SYSROOT")),
                        "-DCMAKE_FIND_ROOT_PATH=%s" % slashify_path(os.getenv("CROSS_CCTOOLS_PATH")),
                        "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER",
                        "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY",
                        "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY",
                        "-DCMAKE_MACOSX_RPATH=@executable_path",
                        "-DCMAKE_OSX_ARCHITECTURES=x86_64",
                        "-DDARWIN_osx_ARCHS=x86_64",
@@ -518,16 +518,19 @@ if __name__ == "__main__":
             symlink(l[0], l[1])
 
     if build_clang_tidy:
         import_clang_tidy(llvm_source_dir)
 
     if not os.path.exists(build_dir):
         os.makedirs(build_dir)
 
+    libcxx_include_dir = os.path.join(llvm_source_dir, "projects",
+                                      "libcxx", "include")
+
     stage1_dir = build_dir + '/stage1'
     stage1_inst_dir = stage1_dir + '/clang'
 
     final_stage_dir = stage1_dir
 
     if is_darwin():
         extra_cflags = []
         extra_cxxflags = ["-stdlib=libc++"]
@@ -577,44 +580,44 @@ if __name__ == "__main__":
                          "-Wl,-dead_strip"]
 
     build_one_stage(
         [cc] + extra_cflags,
         [cxx] + extra_cxxflags,
         [ld] + extra_ldflags,
         ar, ranlib,
         llvm_source_dir, stage1_dir, build_libcxx, osx_cross_compile,
-        build_type, assertions, python_path, gcc_dir)
+        build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
 
     if stages > 1:
         stage2_dir = build_dir + '/stage2'
         stage2_inst_dir = stage2_dir + '/clang'
         final_stage_dir = stage2_dir
         build_one_stage(
             [stage1_inst_dir + "/bin/%s%s" %
                 (cc_name, exe_ext)] + extra_cflags2,
             [stage1_inst_dir + "/bin/%s%s" %
                 (cxx_name, exe_ext)] + extra_cxxflags2,
             [ld] + extra_ldflags,
             ar, ranlib,
             llvm_source_dir, stage2_dir, build_libcxx, osx_cross_compile,
-            build_type, assertions, python_path, gcc_dir)
+            build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
 
     if stages > 2:
         stage3_dir = build_dir + '/stage3'
         final_stage_dir = stage3_dir
         build_one_stage(
             [stage2_inst_dir + "/bin/%s%s" %
                 (cc_name, exe_ext)] + extra_cflags2,
             [stage2_inst_dir + "/bin/%s%s" %
                 (cxx_name, exe_ext)] + extra_cxxflags2,
             [ld] + extra_ldflags,
             ar, ranlib,
             llvm_source_dir, stage3_dir, build_libcxx, osx_cross_compile,
-            build_type, assertions, python_path, gcc_dir)
+            build_type, assertions, python_path, gcc_dir, libcxx_include_dir)
 
     package_name = "clang"
     if build_clang_tidy:
         prune_final_dir_for_clang_tidy(os.path.join(final_stage_dir, "clang"))
         package_name = "clang-tidy"
 
     if is_darwin() or is_windows():
         build_tar_package("tar", package_name + ".tar.bz2", final_stage_dir, "clang")
--- a/build/build-clang/clang-tidy-linux64.json
+++ b/build/build-clang/clang-tidy-linux64.json
@@ -1,10 +1,10 @@
 {
-    "llvm_revision": "290055",
+    "llvm_revision": "292415",
     "stages": "1",
     "build_libcxx": true,
     "build_type": "Release",
     "assertions": false,
     "build_clang_tidy": true,
     "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/trunk",
--- a/build/build-clang/clang-tidy-macosx64.json
+++ b/build/build-clang/clang-tidy-macosx64.json
@@ -1,10 +1,10 @@
 {
-    "llvm_revision": "290055",
+    "llvm_revision": "292415",
     "stages": "1",
     "build_libcxx": true,
     "build_type": "Release",
     "assertions": false,
     "build_clang_tidy": true,
     "osx_cross_compile": true,
     "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
--- a/build/build-clang/clang-tidy-win32.json
+++ b/build/build-clang/clang-tidy-win32.json
@@ -1,10 +1,10 @@
 {
-    "llvm_revision": "290055",
+    "llvm_revision": "292415",
     "stages": "1",
     "build_libcxx": false,
     "build_type": "Release",
     "assertions": false,
     "build_clang_tidy": true,
     "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/trunk",
--- a/build/build-clang/clang-tidy-win64.json
+++ b/build/build-clang/clang-tidy-win64.json
@@ -1,10 +1,10 @@
 {
-    "llvm_revision": "290055",
+    "llvm_revision": "292415",
     "stages": "1",
     "build_libcxx": false,
     "build_type": "Release",
     "assertions": false,
     "build_clang_tidy": true,
     "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/trunk",
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -20,19 +20,19 @@
 # number is the default for the protocol.
 #
 # Unrecognized options are ignored.  Recognized options are "primary" and
 # "privileged", "nocert", "cert=some_cert_nickname", "redir=hostname" and
 # "failHandshake".
 #
 # "primary" denotes a location which is the canonical location of
 # the server; this location is the one assumed for requests which don't
-# otherwise identify a particular origin (e.g. HTTP/1.0 requests).  
+# otherwise identify a particular origin (e.g. HTTP/1.0 requests).
 #
-# "privileged" denotes a location which should have the ability to request 
+# "privileged" denotes a location which should have the ability to request
 # elevated privileges; the default is no privileges.
 #
 # "nocert" makes sense only for https:// hosts and means there is not
 # any certificate automatically generated for this host.
 #
 # "failHandshake" causes the tls handshake to fail (by sending a client hello to
 # the client).
 #
@@ -120,16 +120,17 @@ https://mismatch.untrusted-expired.examp
 
 # This is here so that we don't load the default live bookmark over
 # the network in every test suite.
 http://fxfeeds.mozilla.com:80
 
 # Prevent safebrowsing tests from hitting the network for its-a-trap.html and
 # its-an-attack.html.
 http://www.itisatrap.org:80
+https://www.itisatrap.org:443
 
 #
 # These are subdomains of <ält.example.org>.
 #
 http://sub1.xn--lt-uia.example.org:8000   privileged
 http://sub2.xn--lt-uia.example.org:80     privileged
 http://xn--exmple-cua.test:80             privileged
 http://sub1.xn--exmple-cua.test:80        privileged
--- a/devtools/client/dom/content/dom-view.css
+++ b/devtools/client/dom/content/dom-view.css
@@ -94,21 +94,18 @@ body {
 .treeTable .ordinalLabel {
   color: SlateBlue;
   font-weight: bold;
 }
 
 /******************************************************************************/
 /* Search box */
 .devtools-searchbox {
-  float: right;
-}
-
-.devtools-searchbox:dir(rtl) {
-  float: left;
+  margin-inline-start: auto; /* Align to the right */
+  flex: none; /* Don't flex */
 }
 
 /******************************************************************************/
 /* Theme Dark */
 
 .theme-dark .treeTable > tbody > tr > td {
   border-bottom: none;
 }
--- a/devtools/client/jsonview/components/search-box.js
+++ b/devtools/client/jsonview/components/search-box.js
@@ -38,17 +38,17 @@ define(function (require, exports, modul
     },
 
     doSearch: function (searchBox) {
       this.props.actions.onSearch(searchBox.value);
     },
 
     render: function () {
       return (
-        input({className: "searchBox",
+        input({className: "searchBox devtools-filterinput",
                placeholder: Locale.$STR("jsonViewer.filterJSON"),
                onChange: this.onSearch})
       );
     },
   });
 
   // Exports from this module
   exports.SearchBox = SearchBox;
--- a/devtools/client/jsonview/css/search-box.css
+++ b/devtools/client/jsonview/css/search-box.css
@@ -1,29 +1,17 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
 /******************************************************************************/
 /* Search Box */
 
-.searchBox {
-  height: 18px;
-  font: message-box;
-  background-color: var(--theme-body-background);
-  background-image: url("chrome://devtools/skin/images/filter.svg#filterinput");
-  background-repeat: no-repeat;
-  background-position: 2px center;
-  border: 1px solid var(--theme-splitter-color);
-  border-radius: 2px;
-  color: var(--theme-content-color1);
-  width: 200px;
-  margin-top: 0;
-  margin-inline-end: 1px;
-  float: right;
-  padding-inline-start: 20px;
+.devtools-filterinput {
+  margin-inline-start: auto; /* Align to the right */
 }
 
-.searchBox:dir(rtl) {
-  float: left;
-  background-position: calc(100% - 2px) center;
-}
+/* JSONView doesn't load dark-theme.css */
+.theme-dark .devtools-filterinput {
+  background-color: rgba(24, 29, 32, 1);
+  color: rgba(184, 200, 217, 1);
+}
\ No newline at end of file
--- a/devtools/client/jsonview/css/toolbar.css
+++ b/devtools/client/jsonview/css/toolbar.css
@@ -2,91 +2,42 @@
 /* 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/. */
 
 /******************************************************************************/
 /* Toolbar */
 
 .toolbar {
-  line-height: 20px;
+  display: flex;
   height: 22px;
   font: message-box;
-  padding: 4px 0 3px 0;
+  padding: 1px;
+  padding-inline-start: 2px;
+  background: var(--theme-toolbar-background);
+  border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .toolbar .btn {
-  margin-left: 5px;
-  background-color: #E6E6E6;
-  border: 1px solid rgb(204, 204, 204);
+  margin-inline-start: 5px;
+  color: var(--theme-body-color);
+  background: var(--toolbarbutton-background);
+  border: var(--toolbarbutton-border);
   text-decoration: none;
   display: inline-block;
   text-align: center;
   white-space: nowrap;
   vertical-align: middle;
   cursor: pointer;
   -moz-user-select: none;
   padding: 0 2px;
   border-radius: 2px;
 }
 
-.toolbar .btn::-moz-focus-inner {
-  border: 1px solid transparent;
-}
-
-/******************************************************************************/
-/* Firebug Theme */
-
-.theme-firebug .toolbar {
-  border-bottom: 1px solid rgb(170, 188, 207);
-  background-color: var(--theme-tab-toolbar-background) !important;
-  background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
-}
-
-.theme-firebug .toolbar .btn {
-  border-radius: 2px;
-  color: #141414;
-  background-color: white;
-}
-
-.theme-firebug .toolbar .btn:hover {
-  color: #333;
-  background-color: #e6e6e6;
-  border-color: #adadad;
-}
-
-.theme-firebug .toolbar .btn:active {
-  background-image: none;
-  outline: 0;
-  box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+.toolbar .btn:hover {
+  background: var(--toolbarbutton-hover-background);
+  border: var(--toolbarbutton-hover-border);
 }
 
-/******************************************************************************/
-/* Light Theme & Dark Theme*/
-
-.theme-dark .toolbar,
-.theme-light .toolbar {
-  background-color: var(--theme-toolbar-background);
-  border-bottom: 1px solid var(--theme-splitter-color);
-  padding: 1px;
-  padding-left: 2px;
+.toolbar .btn:not([disabled]):hover:active {
+  background-color: var(--theme-selection-background-semitransparent);
 }
 
-.theme-dark .toolbar .btn,
-.theme-light .toolbar .btn {
-  min-height: 18px;
-  color: var(--theme-content-color1);
-  text-shadow: none;
-  margin: 1px 2px 1px 2px;
-  border: none;
-  background-color: rgba(170, 170, 170, .2); /* --toolbar-tab-hover */
-  transition: background 0.05s ease-in-out;
-}
-
-.theme-dark .toolbar .btn:hover,
-.theme-light .toolbar .btn:hover {
-  background: rgba(170, 170, 170, .3); /* Splitters */
-}
-
-.theme-dark .toolbar .btn:not([disabled]):hover:active,
-.theme-light .toolbar .btn:not([disabled]):hover:active {
-  background: rgba(170, 170, 170, .4); /* --toolbar-tab-hover-active */
-}
--- a/devtools/client/netmonitor/har/har-exporter.js
+++ b/devtools/client/netmonitor/har/har-exporter.js
@@ -54,18 +54,18 @@ const HarExporter = {
    *
    * - jsonpCallback {String}: Default name of JSONP callback (used for
    *   HARP format).
    *
    * - compress {Boolean}: If set to true the final HAR file is zipped.
    *   This represents great disk-space optimization.
    *
    * - defaultFileName {String}: Default name of the target HAR file.
-   *   The default file name supports formatters, see:
-   *   https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleFormat
+   *   The default file name supports the format specifier %date to output the
+   *   current date/time.
    *
    * - defaultLogDir {String}: Default log directory for automated logs.
    *
    * - id {String}: ID of the page (used in the HAR file).
    *
    * - title {String}: Title of the page (used in the HAR file).
    *
    * - forceExport {Boolean}: The result HAR file is created even if
--- a/devtools/client/netmonitor/har/har-utils.js
+++ b/devtools/client/netmonitor/har/har-utils.js
@@ -32,16 +32,27 @@ const OPEN_FLAGS = {
   RDONLY: parseInt("0x01", 16),
   WRONLY: parseInt("0x02", 16),
   CREATE_FILE: parseInt("0x08", 16),
   APPEND: parseInt("0x10", 16),
   TRUNCATE: parseInt("0x20", 16),
   EXCL: parseInt("0x80", 16)
 };
 
+function formatDate(date) {
+  let year = String(date.getFullYear() % 100).padStart(2, "0");
+  let month = String(date.getMonth() + 1).padStart(2, "0");
+  let day = String(date.getDate()).padStart(2, "0");
+  let hour = String(date.getHours()).padStart(2, "0");
+  let minutes = String(date.getMinutes()).padStart(2, "0");
+  let seconds = String(date.getSeconds()).padStart(2, "0");
+
+  return `${year}-${month}-${day} ${hour}-${minutes}-${seconds}`;
+}
+
 /**
  * Helper API for HAR export features.
  */
 var HarUtils = {
   /**
    * Open File Save As dialog and let the user pick the proper file
    * location for generated HAR log.
    */
@@ -63,20 +74,18 @@ var HarUtils = {
     }
 
     return null;
   },
 
   getHarFileName: function (defaultFileName, jsonp, compress) {
     let extension = jsonp ? ".harp" : ".har";
 
-    // Read more about toLocaleFormat & format string.
-    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleFormat
     let now = new Date();
-    let name = now.toLocaleFormat(defaultFileName);
+    let name = defaultFileName.replace(/%date/g, formatDate(now));
     name = name.replace(/\:/gm, "-", "");
     name = name.replace(/\//gm, "_", "");
 
     let fileName = name + extension;
 
     // Default file extension is zip if compressing is on.
     if (compress) {
       fileName += ".zip";
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -171,17 +171,17 @@ pref("devtools.netmonitor.enabled", true
 
 // The default Network Monitor UI settings
 pref("devtools.netmonitor.panes-network-details-width", 550);
 pref("devtools.netmonitor.panes-network-details-height", 450);
 pref("devtools.netmonitor.filters", "[\"all\"]");
 
 // The default Network monitor HAR export setting
 pref("devtools.netmonitor.har.defaultLogDir", "");
-pref("devtools.netmonitor.har.defaultFileName", "Archive %y-%m-%d %H-%M-%S");
+pref("devtools.netmonitor.har.defaultFileName", "Archive %date");
 pref("devtools.netmonitor.har.jsonp", false);
 pref("devtools.netmonitor.har.jsonpCallback", "");
 pref("devtools.netmonitor.har.includeResponseBodies", true);
 pref("devtools.netmonitor.har.compress", false);
 pref("devtools.netmonitor.har.forceExport", false);
 pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
 pref("devtools.netmonitor.har.enableAutoExportToFile", false);
 
--- a/devtools/client/shared/components/tabs/tabs.css
+++ b/devtools/client/shared/components/tabs/tabs.css
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Tabs General Styles */
 
 .tabs {
   height: 100%;
+  background: var(--theme-body-background);
 }
 
 .tabs .tabs-menu {
   display: table;
   list-style: none;
   padding: 0;
   margin: 0;
 }
@@ -41,98 +42,86 @@
 
 .tabs .all-tabs-menu  {
   position: absolute;
   top: 0;
   offset-inline-end: 0;
   width: 15px;
   height: 100%;
   border-inline-start: 1px solid var(--theme-splitter-color);
-  background: url("chrome://devtools/skin/images/dropmarker.svg");
+  background: var(--theme-tab-toolbar-background);
+  background-image: url("chrome://devtools/skin/images/dropmarker.svg");
   background-repeat: no-repeat;
   background-position: center;
-  background-color: var(--theme-tab-toolbar-background);
 }
 
-/* Light Theme */
-
-.theme-dark .tabs,
-.theme-light .tabs {
-  background: var(--theme-body-background);
-}
-
-.theme-dark .tabs .tabs-navigation,
-.theme-light .tabs .tabs-navigation {
+.tabs .tabs-navigation,
+.tabs .tabs-navigation {
   position: relative;
   border-bottom: 1px solid var(--theme-splitter-color);
   background: var(--theme-tab-toolbar-background);
 }
 
 .theme-dark .tabs .tabs-menu-item,
 .theme-light .tabs .tabs-menu-item {
   margin: 0;
   padding: 0;
   border-style: solid;
   border-width: 0;
   border-inline-start-width: 1px;
   border-color: var(--theme-splitter-color);
+  color: var(--theme-content-color1);
 }
 
 .theme-dark .tabs .tabs-menu-item:last-child,
 .theme-light:not(.theme-firebug) .tabs .tabs-menu-item:last-child {
   border-inline-end-width: 1px;
 }
 
 .theme-dark .tabs .tabs-menu-item a,
 .theme-light .tabs .tabs-menu-item a {
-  color: var(--theme-content-color1);
+  color: inherit;
   padding: 3px 15px;
 }
 
 .theme-dark .tabs .tabs-menu-item:hover:not(.is-active),
 .theme-light .tabs .tabs-menu-item:hover:not(.is-active) {
   background-color: var(--toolbar-tab-hover);
 }
 
 .theme-dark .tabs .tabs-menu-item:hover:active:not(.is-active),
 .theme-light .tabs .tabs-menu-item:hover:active:not(.is-active) {
   background-color: var(--toolbar-tab-hover-active);
 }
 
 .theme-dark .tabs .tabs-menu-item.is-active,
 .theme-light .tabs .tabs-menu-item.is-active {
   background-color: var(--theme-selection-background);
-}
-
-.theme-dark .tabs .tabs-menu-item.is-active a,
-.theme-light .tabs .tabs-menu-item.is-active a {
   color: var(--theme-selection-color);
 }
 
 /* Dark Theme */
 
-.theme-dark .tabs .tabs-menu-item a {
+.theme-dark .tabs .tabs-menu-item {
   color: var(--theme-body-color-alt);
 }
 
-.theme-dark .tabs .tabs-menu-item:hover:not(.is-active) a {
+.theme-dark .tabs .tabs-menu-item:hover:not(.is-active) {
   color: #CED3D9;
 }
 
-.theme-dark .tabs .tabs-menu-item:hover:active a {
+.theme-dark .tabs .tabs-menu-item:hover:active {
   color: var(--theme-selection-color);
 }
 
 /* Firebug Theme */
 
 .theme-firebug .tabs .tabs-navigation {
-  background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
   padding-top: 3px;
   padding-left: 3px;
-  border-bottom: 1px solid rgb(170, 188, 207);
 }
 
 .theme-firebug .tabs .tabs-menu {
   margin-bottom: -1px;
 }
 
 .theme-firebug .tabs .tabs-menu-item.is-active,
 .theme-firebug .tabs .tabs-menu-item.is-active:hover {
@@ -147,24 +136,24 @@
 .theme-firebug .tabs .tabs-menu-item a {
   font-family: var(--proportional-font-family);
   font-weight: bold;
   color: var(--theme-body-color);
   border-radius: 4px 4px 0 0;
 }
 
 .theme-firebug .tabs .tabs-menu-item:hover:not(.is-active) a {
-  border: 1px solid #C8C8C8;
+  border: 1px solid var(--theme-splitter-color);
   border-bottom: 1px solid transparent;
   background-color: transparent;
 }
 
 .theme-firebug .tabs .tabs-menu-item.is-active a {
-  background-color: rgb(247, 251, 254);
-  border: 1px solid rgb(170, 188, 207);
+  background-color: var(--theme-toolbar-tab-selected-background);
+  border: 1px solid var(--theme-splitter-color);
   border-bottom-color: transparent;
   color: var(--theme-body-color);
 }
 
 .theme-firebug .tabs .tabs-menu-item:hover:active a {
   background-color: var(--toolbar-tab-hover-active);
 }
 
--- a/devtools/client/themes/common.css
+++ b/devtools/client/themes/common.css
@@ -398,17 +398,17 @@ checkbox:-moz-focusring {
 }
 
 /* Checked/opened icon button background */
 .theme-firebug .devtools-button[checked]:empty,
 .theme-firebug .devtools-button[open]:empty,
 .theme-firebug .devtools-button.checked,
 .theme-firebug .devtools-toolbarbutton:not([label])[checked=true],
 .theme-firebug .devtools-toolbarbutton:not([label])[open=true] {
-  background-color: #C8D8E7;
+  background: var(--toolbarbutton-checked-background);
 }
 
 /* Icon-and-text buttons */
 .devtools-toolbarbutton.icon-and-text .toolbarbutton-text {
   margin-inline-start: .5em !important;
   font-weight: 600;
 }
 
@@ -488,36 +488,38 @@ checkbox:-moz-focusring {
 }
 
 /*
  * Filter buttons
  * @TODO : Fix when https://bugzilla.mozilla.org/show_bug.cgi?id=1255116 lands
  */
 .menu-filter-button {
   -moz-appearance: none;
-  background: rgba(128,128,128,0.1);
-  border: none;
+  background: var(--toolbarbutton-background);
+  border: var(--toolbarbutton-border);
   border-radius: 2px;
   min-width: 0;
   padding: 0 5px;
   margin: 2px;
   color: var(--theme-body-color);
 }
 
 .menu-filter-button:hover {
-  background: rgba(128,128,128,0.2);
+  background: var(--toolbarbutton-hover-background);
+  border: var(--toolbarbutton-hover-border);
 }
 
 .menu-filter-button:hover:active {
   background-color: var(--theme-selection-background-semitransparent);
 }
 
 .menu-filter-button:not(:active).checked {
-  background-color: var(--theme-selection-background);
-  color: var(--theme-selection-color);
+  background: var(--toolbarbutton-checked-background);
+  border: var(--toolbarbutton-checked-border);
+  color: var(--toolbarbutton-checked-color);
 }
 
 /* Text input */
 
 .devtools-textinput,
 .devtools-searchinput,
 .devtools-filterinput {
   -moz-appearance: none;
--- a/devtools/client/themes/firebug-theme.css
+++ b/devtools/client/themes/firebug-theme.css
@@ -34,20 +34,19 @@
 .theme-firebug .cm-tag {color: blue;}
 .theme-firebug .cm-attribute {color: rgb(0, 0, 136);}
 .theme-firebug .cm-header {color: blue;}
 .theme-firebug .cm-quote {color: #090;}
 .theme-firebug .cm-hr {color: #999;}
 .theme-firebug .cm-link {color: #00c;}
 
 .theme-firebug .theme-fg-color3,
-.theme-firebug .cm-s-mozilla .kind-Object .cm-variable{ /* dark blue */
-  color: #006400;
+.theme-firebug .cm-s-mozilla .kind-Object .cm-variable{
+  color: var(--theme-content-color1);
   font-style: normal;
-  font-weight: bold;
 }
 
 .theme-firebug .console-string {
   color: #FF183C;
 }
 
 /* Variables View */
 
@@ -60,59 +59,49 @@
   (both, main and side panels )*/
 
 /* Only apply bottom-border for:
   1) The main tab list.
   2) The side tab list if there is no scroll-box that has its own border.
 
   Use !important to override even the rule in webconsole.css that uses
   ID in the selector. */
-.theme-firebug .devtools-tabbar,
-.theme-firebug .devtools-sidebar-tabs tabs {
-  background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
-  border-bottom: 1px solid rgb(170, 188, 207) !important;
-}
 
 .theme-firebug .devtools-sidebar-tabs tabs {
-  background-color: var(--theme-tab-toolbar-background) !important;
-  background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
+  background: var(--theme-tab-toolbar-background) !important;
+  border-bottom: 1px solid var(--theme-splitter-color) !important;
 }
 
 /* Add a negative bottom margin to overlap bottom border
   of the parent element (see also the next comment for 'tabs') */
 .theme-firebug .devtools-tab,
 .theme-firebug .devtools-sidebar-tabs tab {
   margin: 3px 0 -1px 0;
   padding: 2px 4px 0 4px;
   border: 1px solid transparent !important;
   border-radius: 4px 4px 0 0;
   font-weight: bold;
   color: var(--theme-body-color);
   -moz-box-flex: initial;
   min-width: 0;
 }
 
-/* Also add negative bottom margin for side panel tabs*/
-.theme-firebug .devtools-sidebar-tabs tab {
-}
-
 .theme-firebug .devtools-tab span {
   padding-inline-end: 0;
 }
 
 /* Tweak the margin and padding values differently for sidebar and the main tab bar */
 .theme-firebug .devtools-tab,
 .theme-firebug .devtools-tab.selected {
   padding: 2px 4px 0 4px;
   margin: 3px 1px -1px;
 }
 
 .theme-firebug .devtools-sidebar-tabs tab {
   margin: 3px 0 -1px 0;
-  padding: 2px 0 0 0;
 }
 
 /* In order to hide bottom-border of side panel tabs we need
  to make the parent element overflow visible, so child element
  can move one pixel down to hide the bottom border of the parent. */
 .theme-firebug .devtools-sidebar-tabs tabs {
   overflow: visible;
 }
@@ -120,18 +109,18 @@
 .theme-firebug .devtools-tab:hover,
 .theme-firebug .devtools-sidebar-tabs tab:hover {
   border: 1px solid #C8C8C8 !important;
   border-bottom: 1px solid transparent;
 }
 
 .theme-firebug .devtools-tab.selected,
 .theme-firebug .devtools-sidebar-tabs tab[selected] {
-  background-color: rgb(247, 251, 254);
-  border: 1px solid rgb(170, 188, 207) !important;
+  background-color: var(--theme-toolbar-tab-selected-background);
+  border: 1px solid var(--theme-splitter-color) !important;
   border-bottom-width: 0 !important;
   padding-bottom: 2px;
   color: inherit;
 }
 
 .theme-firebug .devtools-tabbar .devtools-separator,
 .theme-firebug .devtools-tab img {
   display: none;
@@ -186,19 +175,17 @@
 .theme-firebug #command-button-pick {
     top: 6px;
 }
 /* Toolbar */
 
 .theme-firebug .theme-toolbar,
 .theme-firebug toolbar,
 .theme-firebug .devtools-toolbar {
-  border-bottom: 1px solid rgb(170, 188, 207) !important;
-  background-color: var(--theme-tab-toolbar-background) !important;
-  background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
+  background: var(--theme-toolbar-background) !important;
   padding-inline-end: 4px;
 }
 
 /* The vbox for panel content also uses theme-toolbar class from some reason
  but it shouldn't have the padding as defined above, so fix it here */
 .theme-firebug #toolbox-deck > .toolbox-panel.theme-toolbar {
   padding-inline-end: 0;
 }
--- a/devtools/client/themes/memory.css
+++ b/devtools/client/themes/memory.css
@@ -92,16 +92,18 @@ html, body, #app, #memory-tool {
 }
 
 .devtools-toolbar > .toolbar-group > label.label-by > span {
   margin-inline-end: 5px;
 }
 
 .devtools-toolbar > label {
   margin-inline-end: 5px;
+  display: flex;
+  align-items: center;
 }
 
 #select-view {
   margin-inline-start: 5px;
 }
 
 #take-snapshot::before {
   background-image: url(images/command-screenshot.svg);
--- a/devtools/client/themes/netmonitor.css
+++ b/devtools/client/themes/netmonitor.css
@@ -278,16 +278,21 @@
 .theme-firebug .requests-menu-header-button > .button-icon {
   height: 7px;
 }
 
 .theme-firebug .requests-menu-header-button[data-sorted] {
   background-color: #AAC3DC;
 }
 
+:root[platform="linux"].theme-firebug .requests-menu-header-button[data-sorted] {
+  background-color: #FAC8AF !important;
+  color: inherit !important;
+}
+
 .theme-firebug .requests-menu-header:hover:active {
   background-image: linear-gradient(rgba(0, 0, 0, 0.1),
                                     transparent);
 }
 
 
 /* Network requests table: specific column dimensions */
 
@@ -684,17 +689,17 @@
 
 .theme-dark .tabpanel-summary-value {
   color: var(--theme-selection-color);
 }
 
 /* Headers tabpanel */
 
 #headers-tabpanel .summary {
-  background-color: var(--theme-toolbar-background);
+  background: var(--theme-toolbar-background);
 }
 
 /* Response tabpanel */
 
 .response-error-header {
   margin: 0;
   padding: 3px 8px;
   background-color: var(--theme-highlight-red);
--- a/devtools/client/themes/tooltips.css
+++ b/devtools/client/themes/tooltips.css
@@ -345,17 +345,17 @@
   display: flex;
   flex-shrink: 0;
   align-items: center;
   height: 14px;
   border-radius: 3px;
   padding: 2px;
   margin-inline-start: 5px;
   background-color: var(--theme-body-color-alt);
-  color: var(--theme-toolbar-background);
+  color: var(--theme-body-background);
 }
 
 .event-tooltip-attributes {
   margin: 0;
   font-size: 9px;
   padding-top: 2px;
 }
 
--- a/devtools/client/themes/variables.css
+++ b/devtools/client/themes/variables.css
@@ -134,25 +134,26 @@
   --theme-command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#dark-theme-focus);
 }
 
 :root.theme-firebug {
   --theme-body-background: #fff;
   --theme-sidebar-background: #fcfcfc;
   --theme-contrast-background: #e6b064;
 
-  --theme-tab-toolbar-background: #d8eaf9;
-  --theme-toolbar-background: #f0f1f2;
+  --theme-tab-toolbar-background: rgb(240, 240, 240) linear-gradient(rgba(255, 255, 255, 0.8), transparent);
+  --theme-toolbar-background: rgb(240, 240, 240) linear-gradient(rgba(255, 255, 255, 0.8), transparent);
+  --theme-toolbar-tab-selected-background: rgb(253, 253, 253);
   --theme-selection-background: #3399ff;
   --theme-selection-background-semitransparent: rgba(128,128,128,0.2);
   --theme-selection-color: white;
-  --theme-splitter-color: #aabccf;
+  --theme-splitter-color: #bfbfbf;
   --theme-comment: darkgreen;
 
-  --theme-body-color: #000000;
+  --theme-body-color: #252525;
   --theme-body-color-alt: #585959;
   --theme-content-color1: #292e33;
   --theme-content-color2: #8fa1b2;
   --theme-content-color3: #667380;
 
   --theme-highlight-green: #2cbb0f;
   --theme-highlight-blue: #3455db;
   --theme-highlight-bluegrey: #0072ab;
@@ -185,19 +186,43 @@
   /* Header */
   --theme-header-background: #F0F0F0 linear-gradient(to top,
                                                      rgba(0, 0, 0, 0.1),
                                                      transparent) repeat-x;
 
   /* Command line */
   --theme-command-line-image: url(chrome://devtools/skin/images/firebug/commandline-icon.svg);
   --theme-command-line-image-focus: url(chrome://devtools/skin/images/firebug/commandline-icon.svg#focus);
+
+  /* Toolbar buttons */
+  --toolbarbutton-background: transparent linear-gradient(rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.2)) no-repeat;
+  --toolbarbutton-hover-background: transparent;
+  --toolbarbutton-checked-background: linear-gradient(rgba(0, 0, 0, 0.1), transparent);
+  --toolbarbutton-checked-color: var(--theme-body-color);
+  --toolbarbutton-hover-border: 1px solid var(--theme-splitter-color);
+  --toolbarbutton-checked-border: var(--toolbarbutton-hover-border);
+}
+
+:root.theme-firebug[platform="win"] {
+  --theme-tab-toolbar-background: #d8eaf9 linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
+  --theme-toolbar-background: #d8eaf9 linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
+  --theme-toolbar-tab-selected-background: rgb(247, 251, 254);
+  --theme-splitter-color: #aabccf;
 }
 
 :root {
   --theme-focus-border-color-textbox: #0675d3;
   --theme-textbox-box-shadow: rgba(97,181,255,.75);
 
   /* For accessibility purposes we want to enhance the focus styling. This
    * should improve keyboard navigation usability. */
   --theme-focus-outline: 1px dotted var(--theme-focus-outline-color);
   --theme-focus-box-shadow-textbox: 0 0 0 1px var(--theme-textbox-box-shadow);
+
+  --toolbarbutton-background: rgba(128,128,128,0.1);
+  --toolbarbutton-hover-background: rgba(128,128,128,0.2);
+  --toolbarbutton-checked-background: var(--theme-selection-background);
+  --toolbarbutton-checked-color: var(--theme-selection-color);
+
+  --toolbarbutton-border: 1px solid transparent;
+  --toolbarbutton-hover-border: var(--toolbarbutton-border);
+  --toolbarbutton-checked-border: var(--toolbarbutton-border);
 }
--- a/devtools/client/themes/widgets.css
+++ b/devtools/client/themes/widgets.css
@@ -423,37 +423,30 @@ widgets.css is overwritten. */
 }
 
 /* Breadcrumbs Scrolling Buttons */
 
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-up,
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-down {
   padding: 0;
   box-shadow: none;
+  outline: 1px solid var(--theme-splitter-color);
 }
 
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-up:hover,
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-down:hover {
   border: 1px transparent solid !important;
   box-shadow: none !important;
 }
 
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-up:active,
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-down:active {
   background: none !important;
 }
 
-.theme-firebug .breadcrumbs-widget-container .scrollbutton-up > .toolbarbutton-icon {
-  background-image: url(chrome://global/skin/arrow/arrow-lft-sharp.gif);
-}
-
-.theme-firebug .breadcrumbs-widget-container .scrollbutton-down > .toolbarbutton-icon {
-  background-image: url(chrome://global/skin/arrow/arrow-lft-sharp.gif);
-}
-
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-up:not([disabled]):active:hover > .toolbarbutton-icon,
 .theme-firebug .breadcrumbs-widget-container .scrollbutton-down:not([disabled]):active:hover > .toolbarbutton-icon {
   background-position: 0 center;
 }
 
 /* SimpleListWidget */
 
 .simple-list-widget-container {
@@ -1359,27 +1352,37 @@ widgets.css is overwritten. */
   /* Vertically center header label */
   padding-top: 2px !important;
 }
 
 .theme-firebug .devtools-toolbar.table-widget-column-header[sorted] {
   background-color: #AAC3DC !important;
 }
 
+:root[platform="linux"].theme-firebug .devtools-toolbar.table-widget-column-header[sorted] {
+  background-color: #FAC8AF !important;
+  color: inherit !important;
+}
+
 .theme-firebug .devtools-toolbar.table-widget-column-header:hover:active {
   background-image: linear-gradient(rgba(0, 0, 0, 0.1),
                                     transparent);
 }
 
 .theme-firebug .devtools-toolbar.table-widget-column-header[sorted=descending]:not(:active) {
-  background-image: url(chrome://devtools/skin/images/firebug/arrow-down.svg);
+  background-image: url(chrome://devtools/skin/images/firebug/arrow-down.svg) !important;
 }
 
 .theme-firebug .devtools-toolbar.table-widget-column-header[sorted=ascending]:not(:active) {
-  background-image: url(chrome://devtools/skin/images/firebug/arrow-up.svg);
+  background-image: url(chrome://devtools/skin/images/firebug/arrow-up.svg) !important;
+}
+
+.theme-firebug .devtools-toolbar.table-widget-column-header[sorted]:not(:active) {
+  background-position: right !important;
+  background-repeat: no-repeat !important;
 }
 
 /* Cells */
 
 .table-widget-cell {
   width: 100%;
   padding: 3px 4px;
   min-width: 100px;
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -572,17 +572,17 @@ CustomElementRegistry::Define(const nsAS
 
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   JSContext *cx = jsapi.cx();
-  JS::Rooted<JSObject*> constructor(cx, aFunctionConstructor.Callable());
+  JS::Rooted<JSObject*> constructor(cx, aFunctionConstructor.CallableOrNull());
 
   /**
    * 1. If IsConstructor(constructor) is false, then throw a TypeError and abort
    *    these steps.
    */
   // For now, all wrappers are constructable if they are callable. So we need to
   // unwrap constructor to check it is really constructable.
   JS::Rooted<JSObject*> constructorUnwrapped(cx, js::CheckedUnwrap(constructor));
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9056,23 +9056,39 @@ public:
     nsCOMPtr<nsISupports> window = do_QueryReferent(mWindow);
     if (!skipNukeCrossCompartment && window) {
       nsGlobalWindow* win = nsGlobalWindow::FromSupports(window);
       nsGlobalWindow* currentInner = win->IsInnerWindow() ? win : win->GetCurrentInnerWindowInternal();
       NS_ENSURE_TRUE(currentInner, NS_OK);
 
       AutoSafeJSContext cx;
       JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
-      // We only want to nuke wrappers for the chrome->content case
       if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
-        js::NukeCrossCompartmentWrappers(cx,
-                                         BrowserCompartmentMatcher(),
-                                         js::SingleCompartment(js::GetObjectCompartment(obj)),
-                                         win->IsInnerWindow() ? js::DontNukeWindowReferences
-                                                              : js::NukeWindowReferences);
+        JSCompartment* cpt = js::GetObjectCompartment(obj);
+        nsCOMPtr<nsIPrincipal> pc = nsJSPrincipals::get(JS_GetCompartmentPrincipals(cpt));
+
+        nsAutoString addonId;
+        if (NS_SUCCEEDED(pc->GetAddonId(addonId)) && !addonId.IsEmpty()) {
+          // We want to nuke all references to the add-on compartment.
+          js::NukeCrossCompartmentWrappers(cx, js::AllCompartments(),
+                                           js::SingleCompartment(cpt),
+                                           win->IsInnerWindow() ? js::DontNukeWindowReferences
+                                                                : js::NukeWindowReferences);
+
+          // Now mark the compartment as nuked and non-scriptable.
+          auto compartmentPrivate = xpc::CompartmentPrivate::Get(cpt);
+          compartmentPrivate->wasNuked = true;
+          compartmentPrivate->scriptability.Block();
+        } else {
+          // We only want to nuke wrappers for the chrome->content case
+          js::NukeCrossCompartmentWrappers(cx, BrowserCompartmentMatcher(),
+                                           js::SingleCompartment(cpt),
+                                           win->IsInnerWindow() ? js::DontNukeWindowReferences
+                                                                : js::NukeWindowReferences);
+        }
       }
     }
 
     return NS_OK;
   }
 
 private:
   uint64_t mID;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1723,17 +1723,17 @@ GetOrCreateDOMReflectorNoWrap(JSContext*
   return
     GetOrCreateDOMReflectorNoWrapHelper<T>::GetOrCreate(cx, value, rval);
 }
 
 template <class T>
 inline JSObject*
 GetCallbackFromCallbackObject(T* aObj)
 {
-  return aObj->Callback();
+  return aObj->CallbackOrNull();
 }
 
 // Helper for getting the callback JSObject* of a smart ptr around a
 // CallbackObject or a reference to a CallbackObject or something like
 // that.
 template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
 struct GetCallbackFromCallbackObjectHelper
 {
--- a/dom/bindings/CallbackFunction.h
+++ b/dom/bindings/CallbackFunction.h
@@ -35,19 +35,19 @@ public:
   // See CallbackObject for an explanation of the arguments.
   explicit CallbackFunction(JS::Handle<JSObject*> aCallable,
                             JS::Handle<JSObject*> aAsyncStack,
                             nsIGlobalObject* aIncumbentGlobal)
     : CallbackObject(aCallable, aAsyncStack, aIncumbentGlobal)
   {
   }
 
-  JS::Handle<JSObject*> Callable() const
+  JS::Handle<JSObject*> CallableOrNull() const
   {
-    return Callback();
+    return CallbackOrNull();
   }
 
   JS::Handle<JSObject*> CallablePreserveColor() const
   {
     return CallbackPreserveColor();
   }
 
   bool HasGrayCallable() const
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -31,16 +31,54 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(Callback
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CallbackObject)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(CallbackObject)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackObject)
   tmp->DropJSObjects();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncumbentGlobal)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(CallbackObject)
+  JSObject* callback = tmp->CallbackPreserveColor();
+
+  if (!aRemovingAllowed) {
+    // If our callback has been cleared, we can't be part of a garbage cycle.
+    return !callback;
+  }
+
+  // mCallback is always wrapped for the CallbackObject's incumbent global. In
+  // the case where the real callback is in a different compartment, we have a
+  // cross-compartment wrapper, and it will automatically be cut when its
+  // compartment is nuked. In the case where it is in the same compartment, we
+  // have a reference to the real function. Since that means there are no
+  // wrappers to cut, we need to check whether the compartment is still alive,
+  // and drop the references if it is not.
+
+  if (MOZ_UNLIKELY(!callback)) {
+    return true;
+  }
+  auto pvt = xpc::CompartmentPrivate::Get(callback);
+  if (MOZ_LIKELY(tmp->mIncumbentGlobal && pvt) && MOZ_UNLIKELY(pvt->wasNuked)) {
+    // It's not safe to release our global reference or drop our JS objects at
+    // this point, so defer their finalization until CC is finished.
+    AddForDeferredFinalization(new JSObjectsDropper(tmp));
+    DeferredFinalize(tmp->mIncumbentGlobal.forget().take());
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(CallbackObject)
+  return !tmp->mCallback;
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(CallbackObject)
+  return !tmp->mCallback;
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncumbentGlobal)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCreationStack)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mIncumbentJSGlobal)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
@@ -95,18 +133,25 @@ CallbackObject::CallSetup::CallSetup(Cal
 
   // Compute the caller's subject principal (if necessary) early, before we
   // do anything that might perturb the relevant state.
   nsIPrincipal* webIDLCallerPrincipal = nullptr;
   if (aIsJSImplementedWebIDL) {
     webIDLCallerPrincipal = nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
   }
 
+  JSObject* wrappedCallback = aCallback->CallbackPreserveColor();
+  if (!wrappedCallback) {
+    aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
+      NS_LITERAL_CSTRING("Cannot execute callback from a nuked compartment."));
+    return;
+  }
+
   // First, find the real underlying callback.
-  JSObject* realCallback = js::UncheckedUnwrap(aCallback->CallbackPreserveColor());
+  JSObject* realCallback = js::UncheckedUnwrap(wrappedCallback);
   nsIGlobalObject* globalObject = nullptr;
 
   JSContext* cx;
   {
     // Bug 955660: we cannot do "proper" rooting here because we need the
     // global to get a context. Everything here is simple getters that cannot
     // GC, so just paper over the necessary dataflow inversion.
     JS::AutoSuppressGCAnalysis nogc;
@@ -159,23 +204,24 @@ CallbackObject::CallSetup::CallSetup(Cal
                            "incumbent global is being torn down."));
         return;
       }
       mAutoIncumbentScript.emplace(incumbent);
     }
 
     cx = mAutoEntryScript->cx();
 
-    // Unmark the callable (by invoking Callback() and not the CallbackPreserveColor()
-    // variant), and stick it in a Rooted before it can go gray again.
+    // Unmark the callable (by invoking CallbackOrNull() and not the
+    // CallbackPreserveColor() variant), and stick it in a Rooted before it can
+    // go gray again.
     // Nothing before us in this function can trigger a CC, so it's safe to wait
     // until here it do the unmark. This allows us to construct mRootedCallable
     // with the cx from mAutoEntryScript, avoiding the cost of finding another
     // JSContext. (Rooted<> does not care about requests or compartments.)
-    mRootedCallable.emplace(cx, aCallback->Callback());
+    mRootedCallable.emplace(cx, aCallback->CallbackOrNull());
   }
 
   // JS-implemented WebIDL is always OK to run, since it runs with Chrome
   // privileges anyway.
   if (mIsMainThread && !aIsJSImplementedWebIDL) {
     // Check that it's ok to run this callback at all.
     // Make sure to use realCallback to get the global of the callback object,
     // not the wrapper.
@@ -313,17 +359,17 @@ CallbackObjectHolderBase::ToXPCOMCallbac
   }
 
   // We don't init the AutoJSAPI with our callback because we don't want it
   // reporting errors to its global's onerror handlers.
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext* cx = jsapi.cx();
 
-  JS::Rooted<JSObject*> callback(cx, aCallback->Callback());
+  JS::Rooted<JSObject*> callback(cx, aCallback->CallbackOrNull());
 
   JSAutoCompartment ac(cx, callback);
   RefPtr<nsXPCWrappedJS> wrappedJS;
   nsresult rv =
     nsXPCWrappedJS::GetNewOrUsed(callback, aIID, getter_AddRefs(wrappedJS));
   if (NS_FAILED(rv) || !wrappedJS) {
     return nullptr;
   }
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -41,17 +41,17 @@ namespace dom {
  { 0x84, 0xb9, 0x65, 0x06, 0x99, 0xe6, 0x93, 0x2b } }
 
 class CallbackObject : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(DOM_CALLBACKOBJECT_IID)
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CallbackObject)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CallbackObject)
 
   // The caller may pass a global object which will act as an override for the
   // incumbent script settings object when the callback is invoked (overriding
   // the entry point computed from aCallback). If no override is required, the
   // caller should pass null.  |aCx| is used to capture the current
   // stack, which is later used as an async parent when the callback
   // is invoked.  aCx can be nullptr, in which case no stack is
   // captured.
@@ -74,17 +74,25 @@ public:
   // for that purpose.
   explicit CallbackObject(JS::Handle<JSObject*> aCallback,
                           JS::Handle<JSObject*> aAsyncStack,
                           nsIGlobalObject* aIncumbentGlobal)
   {
     Init(aCallback, aAsyncStack, aIncumbentGlobal);
   }
 
-  JS::Handle<JSObject*> Callback() const
+  // This is guaranteed to be non-null from the time the CallbackObject is
+  // created until JavaScript has had a chance to run. It will only return null
+  // after a JavaScript caller has called nukeSandbox on a Sandbox object, and
+  // the cycle collector has had a chance to run.
+  //
+  // This means that any native callee which receives a CallbackObject as an
+  // argument can safely rely on the callback being non-null so long as it
+  // doesn't trigger any scripts before it accesses it.
+  JS::Handle<JSObject*> CallbackOrNull() const
   {
     mCallback.exposeToActiveJS();
     return CallbackPreserveColor();
   }
 
   JSObject* GetCreationStack() const
   {
     return mCreationStack;
@@ -108,17 +116,17 @@ public:
   {
     // Calling fromMarkedLocation() is safe because we trace our mCallback, and
     // because the value of mCallback cannot change after if has been set.
     return JS::Handle<JSObject*>::fromMarkedLocation(mCallback.address());
   }
 
   /*
    * If the callback is known to be non-gray, then this method can be
-   * used instead of Callback() to avoid the overhead of
+   * used instead of CallbackOrNull() to avoid the overhead of
    * ExposeObjectToActiveJS().
    */
   JS::Handle<JSObject*> CallbackKnownNotGray() const
   {
     MOZ_ASSERT(!JS::ObjectIsMarkedGray(mCallback));
     return CallbackPreserveColor();
   }
 
@@ -155,23 +163,43 @@ protected:
   explicit CallbackObject(CallbackObject* aCallbackObject)
   {
     Init(aCallbackObject->mCallback, aCallbackObject->mCreationStack,
          aCallbackObject->mIncumbentGlobal);
   }
 
   bool operator==(const CallbackObject& aOther) const
   {
-    JSObject* thisObj =
-      js::UncheckedUnwrap(CallbackPreserveColor());
-    JSObject* otherObj =
-      js::UncheckedUnwrap(aOther.CallbackPreserveColor());
+    JSObject* wrappedThis = CallbackPreserveColor();
+    JSObject* wrappedOther = aOther.CallbackPreserveColor();
+    if (!wrappedThis || !wrappedOther) {
+      return this == &aOther;
+    }
+
+    JSObject* thisObj = js::UncheckedUnwrap(wrappedThis);
+    JSObject* otherObj = js::UncheckedUnwrap(wrappedOther);
     return thisObj == otherObj;
   }
 
+  class JSObjectsDropper final
+  {
+  public:
+    explicit JSObjectsDropper(CallbackObject* aHolder)
+      : mHolder(aHolder)
+    {}
+
+    ~JSObjectsDropper()
+    {
+      mHolder->DropJSObjects();
+    }
+
+  private:
+    RefPtr<CallbackObject> mHolder;
+  };
+
 private:
   inline void InitNoHold(JSObject* aCallback, JSObject* aCreationStack,
                          nsIGlobalObject* aIncumbentGlobal)
   {
     MOZ_ASSERT(aCallback && !mCallback);
     // Set script objects before we hold, on the off chance that a GC could
     // somehow happen in there... (which would be pretty odd, granted).
     mCallback = aCallback;
@@ -519,17 +547,19 @@ NS_DEFINE_STATIC_IID_ACCESSOR(CallbackOb
 
 template<class T, class U>
 inline void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
                             CallbackObjectHolder<T, U>& aField,
                             const char* aName,
                             uint32_t aFlags = 0)
 {
-  CycleCollectionNoteChild(aCallback, aField.GetISupports(), aName, aFlags);
+  if (aField) {
+    CycleCollectionNoteChild(aCallback, aField.GetISupports(), aName, aFlags);
+  }
 }
 
 template<class T, class U>
 void
 ImplCycleCollectionUnlink(CallbackObjectHolder<T, U>& aField)
 {
   aField.UnlinkSelf();
 }
@@ -557,20 +587,20 @@ public:
 
   // But nullptr can't use the above template, because it doesn't know which S
   // to select.  So we need a special overload for nullptr.
   void operator=(decltype(nullptr) arg)
   {
     this->get().operator=(arg);
   }
 
-  // Codegen relies on being able to do Callback() on us.
-  JS::Handle<JSObject*> Callback() const
+  // Codegen relies on being able to do CallbackOrNull() on us.
+  JS::Handle<JSObject*> CallbackOrNull() const
   {
-    return this->get()->Callback();
+    return this->get()->CallbackOrNull();
   }
 
   ~RootedCallback()
   {
     // Ensure that our callback starts holding on to its own JS objects as
     // needed.  We really do need to check that things are initialized even when
     // T is OwningNonNull, because we might be running before the OwningNonNull
     // ever got assigned to!
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4248,17 +4248,19 @@ class CastableObjectUnwrapper():
             self.substitution["codeOnFailure"] = fill(
                 """
                 // Be careful to not wrap random DOM objects here, even if
                 // they're wrapped in opaque security wrappers for some reason.
                 // XXXbz Wish we could check for a JS-implemented object
                 // that already has a content reflection...
                 if (!IsDOMObject(js::UncheckedUnwrap(${source}))) {
                   nsCOMPtr<nsIGlobalObject> contentGlobal;
-                  if (!GetContentGlobalForJSImplementedObject(cx, Callback(), getter_AddRefs(contentGlobal))) {
+                  JS::Handle<JSObject*> callback = CallbackOrNull();
+                  if (!callback ||
+                      !GetContentGlobalForJSImplementedObject(cx, callback, getter_AddRefs(contentGlobal))) {
                     $*{exceptionCode}
                   }
                   JS::Rooted<JSObject*> jsImplSourceObj(cx, ${source});
                   ${target} = new ${type}(jsImplSourceObj, contentGlobal);
                 } else {
                   $*{codeOnFailure}
                 }
                 """,
@@ -15116,21 +15118,21 @@ class CGJSImplClass(CGBindingImplClass):
         return fill(
             """
             JS::Rooted<JSObject*> obj(aCx, ${name}Binding::Wrap(aCx, this, aGivenProto));
             if (!obj) {
               return nullptr;
             }
 
             // Now define it on our chrome object
-            JSAutoCompartment ac(aCx, mImpl->Callback());
+            JSAutoCompartment ac(aCx, mImpl->CallbackOrNull());
             if (!JS_WrapObject(aCx, &obj)) {
               return nullptr;
             }
-            if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", obj, 0)) {
+            if (!JS_DefineProperty(aCx, mImpl->CallbackOrNull(), "__DOM_IMPL__", obj, 0)) {
               return nullptr;
             }
             return obj;
             """,
             name=self.descriptor.name)
 
     def getGetParentObjectReturnType(self):
         return "nsISupports*"
--- a/dom/bindings/DOMString.h
+++ b/dom/bindings/DOMString.h
@@ -17,43 +17,54 @@
 
 namespace mozilla {
 namespace dom {
 
 /**
  * A class for representing string return values.  This can be either passed to
  * callees that have an nsString or nsAString out param or passed to a callee
  * that actually knows about this class and can work with it.  Such a callee may
- * call SetStringBuffer or SetOwnedString or SetOwnedAtom on this object, but
- * only if it plans to keep holding a strong ref to the internal stringbuffer!
+ * call SetStringBuffer or SetEphemeralStringBuffer or SetOwnedString or
+ * SetOwnedAtom on this object.  It's only OK to call
+ * SetStringBuffer/SetOwnedString/SetOwnedAtom if the caller of the method in
+ * question plans to keep holding a strong ref to the stringbuffer involved,
+ * whether it's a raw nsStringBuffer, or stored inside the string or atom being
+ * passed.  In the string/atom cases that means the caller must own the string
+ * or atom, and not mutate it (in the string case) for the lifetime of the
+ * DOMString.
  *
  * The proper way to store a value in this class is to either to do nothing
- * (which leaves this as an empty string), to call SetStringBuffer with a
- * non-null stringbuffer, to call SetOwnedString, to call SetOwnedAtom, to call
- * SetNull(), or to call AsAString() and set the value in the resulting
- * nsString.  These options are mutually exclusive! Don't do more than one of
- * them.
+ * (which leaves this as an empty string), to call
+ * SetStringBuffer/SetEphemeralStringBuffer with a non-null stringbuffer, to
+ * call SetOwnedString, to call SetOwnedAtom, to call SetNull(), or to call
+ * AsAString() and set the value in the resulting nsString.  These options are
+ * mutually exclusive! Don't do more than one of them.
  *
  * The proper way to extract a value is to check IsNull().  If not null, then
  * check HasStringBuffer().  If that's true, check for a zero length, and if the
  * length is nonzero call StringBuffer().  If the length is zero this is the
  * empty string.  If HasStringBuffer() returns false, call AsAString() and get
  * the value from that.
  */
 class MOZ_STACK_CLASS DOMString {
 public:
   DOMString()
     : mStringBuffer(nullptr)
     , mLength(0)
     , mIsNull(false)
+    , mStringBufferOwned(false)
   {}
   ~DOMString()
   {
     MOZ_ASSERT(!mString || !mStringBuffer,
                "Shouldn't have both present!");
+    if (mStringBufferOwned) {
+      MOZ_ASSERT(mStringBuffer);
+      mStringBuffer->Release();
+    }
   }
 
   operator nsString&()
   {
     return AsAString();
   }
 
   // It doesn't make any sense to convert a DOMString to a const nsString or
@@ -76,17 +87,19 @@ public:
     MOZ_ASSERT(!mString || !mStringBuffer,
                "Shouldn't have both present!");
     MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
     return !mString;
   }
 
   // Get the stringbuffer.  This can only be called if HasStringBuffer()
   // returned true and StringBufferLength() is nonzero.  If that's true, it will
-  // never return null.
+  // never return null.  Note that constructing a string from this
+  // nsStringBuffer with length given by StringBufferLength() might give you
+  // something that is not null-terminated.
   nsStringBuffer* StringBuffer() const
   {
     MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
     MOZ_ASSERT(HasStringBuffer(),
                "Don't ask for the stringbuffer if we don't have it");
     MOZ_ASSERT(StringBufferLength() != 0, "Why are you asking for this?");
     MOZ_ASSERT(mStringBuffer,
                "If our length is nonzero, we better have a stringbuffer.");
@@ -96,26 +109,52 @@ public:
   // Get the length of the stringbuffer.  Can only be called if
   // HasStringBuffer().
   uint32_t StringBufferLength() const
   {
     MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer");
     return mLength;
   }
 
+  // Tell the DOMString to relinquish ownership of its nsStringBuffer to the
+  // caller.  Can only be called if HasStringBuffer().
+  void RelinquishBufferOwnership()
+  {
+    MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer");
+    if (mStringBufferOwned) {
+      // Just hand that ref over.
+      mStringBufferOwned = false;
+    } else {
+      // Caller should end up holding a ref.
+      mStringBuffer->AddRef();
+    }
+  }
+
+  // Initialize the DOMString to a (nsStringBuffer, length) pair.  The length
+  // does NOT have to be the full length of the (null-terminated) string in the
+  // nsStringBuffer.
   void SetStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength)
   {
     MOZ_ASSERT(mString.isNothing(), "We already have a string?");
     MOZ_ASSERT(!mIsNull, "We're already set as null");
     MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?");
     MOZ_ASSERT(aStringBuffer, "Why are we getting null?");
     mStringBuffer = aStringBuffer;
     mLength = aLength;
   }
 
+  // Like SetStringBuffer, but holds a reference to the nsStringBuffer.
+  void SetEphemeralStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength)
+  {
+    // We rely on SetStringBuffer to ensure our state invariants.
+    SetStringBuffer(aStringBuffer, aLength);
+    aStringBuffer->AddRef();
+    mStringBufferOwned = true;
+  }
+
   void SetOwnedString(const nsAString& aString)
   {
     MOZ_ASSERT(mString.isNothing(), "We already have a string?");
     MOZ_ASSERT(!mIsNull, "We're already set as null");
     MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?");
     nsStringBuffer* buf = nsStringBuffer::FromString(aString);
     if (buf) {
       SetStringBuffer(buf, aString.Length());
@@ -163,17 +202,28 @@ public:
   void ToString(nsAString& aString)
   {
     if (IsNull()) {
       SetDOMStringToNull(aString);
     } else if (HasStringBuffer()) {
       if (StringBufferLength() == 0) {
         aString.Truncate();
       } else {
-        StringBuffer()->ToString(StringBufferLength(), aString);
+        // Don't share the nsStringBuffer with aString if the result would not
+        // be null-terminated.
+        nsStringBuffer* buf = StringBuffer();
+        uint32_t len = StringBufferLength();
+        auto chars = static_cast<char16_t*>(buf->Data());
+        if (chars[len] == '\0') {
+          // Safe to share the buffer.
+          buf->ToString(len, aString);
+        } else {
+          // We need to copy, unfortunately.
+          aString.Assign(chars, len);
+        }
       }
     } else {
       aString = AsAString();
     }
   }
 
 private:
   // We need to be able to act like a string as needed
@@ -181,14 +231,15 @@ private:
 
   // For callees that know we exist, we can be a stringbuffer/length/null-flag
   // triple.
   nsStringBuffer* MOZ_UNSAFE_REF("The ways in which this can be safe are "
                                  "documented above and enforced through "
                                  "assertions") mStringBuffer;
   uint32_t mLength;
   bool mIsNull;
+  bool mStringBufferOwned;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_DOMString_h
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -53,17 +53,17 @@ ThrowExceptionValueIfSafe(JSContext* aCx
   }
 
   // We could probably Throw(aCx, NS_ERROR_UNEXPECTED) here, and it would do the
   // right thing due to there not being an existing exception on the runtime at
   // this point, but it's clearer to explicitly do the thing we want done.  This
   // is also why we don't just call ThrowExceptionObject on the Exception we
   // create: it would do the right thing, but that fact is not obvious.
   RefPtr<Exception> syntheticException =
-    CreateException(aCx, NS_ERROR_UNEXPECTED);
+    CreateException(NS_ERROR_UNEXPECTED);
   JS::Rooted<JS::Value> syntheticVal(aCx);
   if (!GetOrCreateDOMReflector(aCx, syntheticException, &syntheticVal)) {
     return;
   }
   MOZ_ASSERT(syntheticVal.isObject() &&
              !js::IsWrapper(&syntheticVal.toObject()),
              "Must have a reflector here, not a wrapper");
   JS_SetPendingException(aCx, syntheticVal);
@@ -158,17 +158,17 @@ Throw(JSContext* aCx, nsresult aRv, cons
     if (NS_SUCCEEDED(existingException->GetResult(&nr)) &&
         aRv == nr) {
       // Reuse the existing exception.
       ThrowExceptionObject(aCx, existingException);
       return false;
     }
   }
 
-  RefPtr<Exception> finalException = CreateException(aCx, aRv, aMessage);
+  RefPtr<Exception> finalException = CreateException(aRv, aMessage);
   MOZ_ASSERT(finalException);
 
   ThrowExceptionObject(aCx, finalException);
   return false;
 }
 
 void
 ThrowAndReport(nsPIDOMWindowInner* aWindow, nsresult aRv)
@@ -179,17 +179,17 @@ ThrowAndReport(nsPIDOMWindowInner* aWind
   if (NS_WARN_IF(!jsapi.Init(aWindow))) {
     return;
   }
 
   Throw(jsapi.cx(), aRv);
 }
 
 already_AddRefed<Exception>
-CreateException(JSContext* aCx, nsresult aRv, const nsACString& aMessage)
+CreateException(nsresult aRv, const nsACString& aMessage)
 {
   // Do we use DOM exceptions for this error code?
   switch (NS_ERROR_GET_MODULE(aRv)) {
   case NS_ERROR_MODULE_DOM:
   case NS_ERROR_MODULE_SVG:
   case NS_ERROR_MODULE_DOM_XPATH:
   case NS_ERROR_MODULE_DOM_INDEXEDDB:
   case NS_ERROR_MODULE_DOM_FILEHANDLE:
--- a/dom/bindings/Exceptions.h
+++ b/dom/bindings/Exceptions.h
@@ -36,24 +36,23 @@ ThrowAndReport(nsPIDOMWindowInner* aWind
 
 // Both signatures of ThrowExceptionObject guarantee that an exception is set on
 // aCx before they return.
 void
 ThrowExceptionObject(JSContext* aCx, Exception* aException);
 void
 ThrowExceptionObject(JSContext* aCx, nsIException* aException);
 
-// Create an exception object for the given nsresult and message but don't set
-// it pending on aCx.  If we're throwing a DOMException and aMessage is empty,
-// the default message for the nsresult in question will be used.
+// Create an exception object for the given nsresult and message. If we're
+// throwing a DOMException and aMessage is empty, the default message for the
+// nsresult in question will be used.
 //
 // This never returns null.
 already_AddRefed<Exception>
-CreateException(JSContext* aCx, nsresult aRv,
-                const nsACString& aMessage = EmptyCString());
+CreateException(nsresult aRv, const nsACString& aMessage = EmptyCString());
 
 // aMaxDepth can be used to define a maximal depth for the stack trace. If the
 // value is -1, a default maximal depth will be selected.  Will return null if
 // there is no JS stack right now.
 already_AddRefed<nsIStackFrame>
 GetCurrentJSStack(int32_t aMaxDepth = -1);
 
 // Internal stuff not intended to be widely used.
--- a/dom/bindings/ToJSValue.cpp
+++ b/dom/bindings/ToJSValue.cpp
@@ -39,17 +39,17 @@ ToJSValue(JSContext* aCx, const nsAStrin
 }
 
 
 bool
 ToJSValue(JSContext* aCx,
           nsresult aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
-  RefPtr<Exception> exception = CreateException(aCx, aArgument);
+  RefPtr<Exception> exception = CreateException(aArgument);
   return ToJSValue(aCx, exception, aValue);
 }
 
 bool
 ToJSValue(JSContext* aCx,
           ErrorResult& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -127,17 +127,17 @@ ToJSValue(JSContext* aCx,
 MOZ_MUST_USE inline bool
 ToJSValue(JSContext* aCx,
           CallbackObject& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
-  aValue.setObject(*aArgument.Callback());
+  aValue.setObjectOrNull(aArgument.CallbackOrNull());
 
   return MaybeWrapValue(aCx, aValue);
 }
 
 // Accept objects that inherit from nsWrapperCache (e.g. most
 // DOM objects).
 template <class T>
 MOZ_MUST_USE
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -2258,21 +2258,26 @@ Console::NotifyHandler(JSContext* aCx, c
   MOZ_ASSERT(aCallData);
 
   if (!mConsoleEventNotifier) {
     return;
   }
 
   JS::Rooted<JS::Value> value(aCx);
 
+  JS::Rooted<JSObject*> callable(aCx, mConsoleEventNotifier->CallableOrNull());
+  if (NS_WARN_IF(!callable)) {
+    return;
+  }
+
   // aCx and aArguments are in the same compartment because this method is
   // called directly when a Console.something() runs.
   // mConsoleEventNotifier->Callable() is the scope where value will be sent to.
   if (NS_WARN_IF(!PopulateConsoleNotificationInTheTargetScope(aCx, aArguments,
-                                                              mConsoleEventNotifier->Callable(),
+                                                              callable,
                                                               &value,
                                                               aCallData))) {
     return;
   }
 
   JS::Rooted<JS::Value> ignored(aCx);
   mConsoleEventNotifier->Call(value, &ignored);
 }
--- a/dom/events/DOMEventTargetHelper.cpp
+++ b/dom/events/DOMEventTargetHelper.cpp
@@ -316,17 +316,17 @@ DOMEventTargetHelper::SetEventHandler(ns
 
 void
 DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
                                       JSContext* aCx,
                                       JS::Value* aValue)
 {
   EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString());
   if (handler) {
-    *aValue = JS::ObjectValue(*handler->Callable());
+    *aValue = JS::ObjectOrNullValue(handler->CallableOrNull());
   } else {
     *aValue = JS::NullValue();
   }
 }
 
 nsresult
 DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
--- a/dom/events/EventListenerService.cpp
+++ b/dom/events/EventListenerService.cpp
@@ -133,17 +133,17 @@ EventListenerInfo::GetJSVal(JSContext* a
     aAc.emplace(aCx, object);
     aJSVal.setObject(*object);
     return true;
   }
 
   nsCOMPtr<JSEventHandler> jsHandler = do_QueryInterface(mListener);
   if (jsHandler && jsHandler->GetTypedEventHandler().HasEventHandler()) {
     JS::Handle<JSObject*> handler =
-      jsHandler->GetTypedEventHandler().Ptr()->Callable();
+      jsHandler->GetTypedEventHandler().Ptr()->CallableOrNull();
     if (handler) {
       aAc.emplace(aCx, handler);
       aJSVal.setObject(*handler);
       return true;
     }
   }
   return false;
 }
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1436,16 +1436,17 @@ StartMacOSContentSandbox()
     if (NS_FAILED(rv) || profileDirPath.IsEmpty()) {
       MOZ_CRASH("Failed to get profile path");
     }
   }
 
   MacSandboxInfo info;
   info.type = MacSandboxType_Content;
   info.level = info.level = sandboxLevel;
+  info.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled", true);
   info.appPath.assign(appPath.get());
   info.appBinaryPath.assign(appBinaryPath.get());
   info.appDir.assign(appDir.get());
   info.appTempDir.assign(tempDirPath.get());
 
   if (profileDir) {
     info.hasSandboxedProfile = true;
     info.profileDir.assign(profileDirPath.get());
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1603,31 +1603,32 @@ ContentParent::ShouldKeepProcessAlive() 
     return false;
   }
 
   // If we have already been marked as dead, don't prevent shutdown.
   if (!IsAlive()) {
     return false;
   }
 
-  // Only keep processes for the default remote type alive.
-  if (!mRemoteType.EqualsLiteral(DEFAULT_REMOTE_TYPE)) {
-    return false;
-  }
-
   auto contentParents = sBrowserContentParents->Get(mRemoteType);
   if (!contentParents) {
     return false;
   }
 
-  // We might want to keep alive some content processes for testing, because of
-  // performance reasons.
+  // We might want to keep alive some content processes alive during test runs,
+  // for performance reasons. This should never be used in production.
   // We don't want to alter behavior if the pref is not set, so default to 0.
-  int32_t processesToKeepAlive =
-    Preferences::GetInt("dom.ipc.keepProcessesAlive", 0);
+  int32_t processesToKeepAlive = 0;
+
+  nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive.");
+  keepAlivePref.Append(NS_ConvertUTF16toUTF8(mRemoteType));
+  if (NS_FAILED(Preferences::GetInt(keepAlivePref.get(), &processesToKeepAlive))) {
+    return false;
+  }
+
   int32_t numberOfAliveProcesses = contentParents->Length();
 
   return numberOfAliveProcesses <= processesToKeepAlive;
 }
 
 void
 ContentParent::NotifyTabDestroying(const TabId& aTabId,
                                    const ContentParentId& aCpId)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -33,16 +33,17 @@
 
 #define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
 
 #define NO_REMOTE_TYPE ""
 
 // These must match the similar ones in E10SUtils.jsm.
 #define DEFAULT_REMOTE_TYPE "web"
 #define FILE_REMOTE_TYPE "file"
+#define EXTENSION_REMOTE_TYPE "extension"
 
 // This must start with the DEFAULT_REMOTE_TYPE above.
 #define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
 
 class nsConsoleService;
 class nsICycleCollectorLogSink;
 class nsIDumpGCAndCCLogsCallback;
 class nsITabParent;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -911,25 +911,25 @@ TabParent::RecvPDocAccessibleConstructor
     // There should always be an outer doc accessible child of the outer
     // document containing the child.
     MOZ_ASSERT(aParentID);
     if (!aParentID) {
       return IPC_FAIL_NO_REASON(this);
     }
 
     auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
-    bool added = parentDoc->AddChildDoc(doc, aParentID);
+    mozilla::ipc::IPCResult added = parentDoc->AddChildDoc(doc, aParentID);
 #ifdef XP_WIN
     MOZ_ASSERT(aDocCOMProxy.IsNull());
     if (added) {
       a11y::WrapperFor(doc)->SetID(aMsaaID);
     }
 #endif
     if (!added) {
-      return IPC_FAIL_NO_REASON(this);
+      return added;
     }
     return IPC_OK();
   } else {
     // null aParentDoc means this document is at the top level in the child
     // process.  That means it makes no sense to get an id for an accessible
     // that is its parent.
     MOZ_ASSERT(!aParentID);
     if (aParentID) {
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -295,20 +295,20 @@ MediaDecoder::NotifyOwnerActivityChanged
   MediaDecoderOwner* owner = GetOwner();
   NS_ENSURE_TRUE_VOID(owner);
 
   dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE_VOID(element);
 
   RefPtr<LayerManager> layerManager =
     nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
-  NS_ENSURE_TRUE_VOID(layerManager);
-
-  RefPtr<KnowsCompositor> knowsCompositor = layerManager->AsShadowForwarder();
-  mCompositorUpdatedEvent.Notify(knowsCompositor);
+  if (layerManager) {
+    RefPtr<KnowsCompositor> knowsCompositor = layerManager->AsShadowForwarder();
+    mCompositorUpdatedEvent.Notify(knowsCompositor);
+  }
 }
 
 void
 MediaDecoder::Pause()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   if (mPlayState == PLAY_STATE_LOADING || IsEnded()) {
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -226,16 +226,17 @@ GMPChild::SetMacSandboxInfo(MacSandboxPl
   }
   nsAutoCString appPath, appBinaryPath;
   if (!GetAppPaths(appPath, appBinaryPath)) {
     return false;
   }
 
   MacSandboxInfo info;
   info.type = MacSandboxType_Plugin;
+  info.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled", true);
   info.pluginInfo.type = aPluginType;
   info.pluginInfo.pluginPath.assign(pluginDirectoryPath.get());
   info.pluginInfo.pluginBinaryPath.assign(pluginFilePath.get());
   info.appPath.assign(appPath.get());
   info.appBinaryPath.assign(appBinaryPath.get());
 
   mGMPLoader->SetSandboxInfo(&info);
   return true;
--- a/dom/media/ipc/RemoteVideoDecoder.cpp
+++ b/dom/media/ipc/RemoteVideoDecoder.cpp
@@ -159,17 +159,17 @@ RemoteDecoderModule::DecoderNeedsConvers
 }
 
 already_AddRefed<MediaDataDecoder>
 RemoteDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
 {
   if (!MediaPrefs::PDMUseGPUDecoder() ||
       !aParams.mKnowsCompositor ||
       aParams.mKnowsCompositor->GetTextureFactoryIdentifier().mParentProcessType != GeckoProcessType_GPU) {
-    return nullptr;
+    return mWrapped->CreateVideoDecoder(aParams);
   }
 
   MediaDataDecoderCallback* callback = aParams.mCallback;
   MOZ_ASSERT(callback->OnReaderTaskQueue());
   RefPtr<RemoteVideoDecoder> object = new RemoteVideoDecoder(callback);
 
   SynchronousTask task("InitIPDL");
   bool success;
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -24,16 +24,20 @@ class AudioInfo;
 class VideoInfo;
 class MediaRawData;
 class DecoderDoctorDiagnostics;
 
 namespace layers {
 class ImageContainer;
 } // namespace layers
 
+namespace dom {
+class RemoteDecoderModule;
+}
+
 class MediaDataDecoder;
 class MediaDataDecoderCallback;
 class TaskQueue;
 class CDMProxy;
 
 static LazyLogModule sPDMLog("PlatformDecoderModule");
 
 struct MOZ_STACK_CLASS CreateDecoderParams final {
@@ -140,16 +144,17 @@ public:
   virtual ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const = 0;
 
 protected:
   PlatformDecoderModule() {}
   virtual ~PlatformDecoderModule() {}
 
   friend class H264Converter;
   friend class PDMFactory;
+  friend class dom::RemoteDecoderModule;
 
   // Creates a Video decoder. The layers backend is passed in so that
   // decoders can determine whether hardware accelerated decoding can be used.
   // Asynchronous decoding of video should be done in runnables dispatched
   // to aVideoTaskQueue. If the task queue isn't needed, the decoder should
   // not hold a reference to it.
   // Output and errors should be returned to the reader via aCallback.
   // On Windows the task queue's threads in have MSCOM initialized with
--- a/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html
+++ b/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html
@@ -81,46 +81,48 @@
         },
         function PC_REMOTE_CHECK_SIZE_1() {
           var vlocal = test.pcLocal.localMediaElements[0];
           var vremote = test.pcRemote.remoteMediaElements[0];
           ok(vlocal, "Should have local video element for pcLocal");
           ok(vremote, "Should have remote video element for pcRemote");
           ok(vlocal.videoWidth > 0, "source width is positive");
           ok(vlocal.videoHeight > 0, "source height is positive");
-          is(vremote.videoWidth, vlocal.videoWidth / 2, "sink is same width as source");
-          is(vremote.videoHeight, vlocal.videoHeight / 2, "sink is same height as source");
+          is(vremote.videoWidth, vlocal.videoWidth / 2, "sink is 1/2 width of source");
+          is(vremote.videoHeight, vlocal.videoHeight / 2, "sink is 1/2 height of source");
         },
         function PC_REMOTE_SET_RTP_SECOND_RID(test) {
           // Now, cause pcRemote to filter out everything but the second SSRC.
           // This lets only the other simulcast stream through.
           selectRecvSsrc(test.pcRemote, 1);
         },
         function PC_REMOTE_WAIT_FOR_SECOND_MEDIA_FLOW(test) {
           return test.pcRemote.waitForMediaFlow();
         },
+        function PC_REMOTE_WAIT_FOR_FRAMES_2() {
+          var vremote = test.pcRemote.remoteMediaElements[0];
+          ok(vremote, "Should have remote video element for pcRemote");
+          return helper.waitForFrames(vremote);
+        },
+        // For some reason, even though we're getting a 25x25 stream, sometimes
+        // the resolution isn't updated on the video element on the first frame.
+        function PC_REMOTE_WAIT_FOR_FRAMES_3() {
+          var vremote = test.pcRemote.remoteMediaElements[0];
+          ok(vremote, "Should have remote video element for pcRemote");
+          return helper.waitForFrames(vremote);
+        },
         function PC_REMOTE_CHECK_SIZE_2() {
           var vlocal = test.pcLocal.localMediaElements[0];
           var vremote = test.pcRemote.remoteMediaElements[0];
           ok(vlocal, "Should have local video element for pcLocal");
           ok(vremote, "Should have remote video element for pcRemote");
           ok(vlocal.videoWidth > 0, "source width is positive");
           ok(vlocal.videoHeight > 0, "source height is positive");
-          is(vremote.videoWidth, vlocal.videoWidth / 2, "sink is 1/2 width of source");
-          is(vremote.videoHeight, vlocal.videoHeight / 2,  "sink is 1/2 height of source");
-        },
-        function PC_REMOTE_SET_RTP_NONEXISTENT_RID(test) {
-          // Now, cause pcRemote to filter out everything, just to make sure
-          // selectRecvSsrc is working.
-          selectRecvSsrc(test.pcRemote, 2);
-        },
-        function PC_REMOTE_ENSURE_NO_FRAMES() {
-          var vremote = test.pcRemote.remoteMediaElements[0];
-          ok(vremote, "Should have remote video element for pcRemote");
-          return helper.verifyNoFrames(vremote);
+          is(vremote.videoWidth, vlocal.videoWidth, "sink is same width as source");
+          is(vremote.videoHeight, vlocal.videoHeight,  "sink is same height as source");
         },
       ]);
 
       return test.run();
   })
   .catch(e => ok(false, "unexpected failure: " + e)));
 </script>
 </pre>
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -196,26 +196,26 @@ Promise::Then(JSContext* aCx,
   JS::Rooted<JSObject*> promise(aCx, PromiseObj());
   if (!JS_WrapObject(aCx, &promise)) {
     aRv.NoteJSContextException(aCx);
     return;
   }
 
   JS::Rooted<JSObject*> resolveCallback(aCx);
   if (aResolveCallback) {
-    resolveCallback = aResolveCallback->Callback();
+    resolveCallback = aResolveCallback->CallbackOrNull();
     if (!JS_WrapObject(aCx, &resolveCallback)) {
       aRv.NoteJSContextException(aCx);
       return;
     }
   }
 
   JS::Rooted<JSObject*> rejectCallback(aCx);
   if (aRejectCallback) {
-    rejectCallback = aRejectCallback->Callback();
+    rejectCallback = aRejectCallback->CallbackOrNull();
     if (!JS_WrapObject(aCx, &rejectCallback)) {
       aRv.NoteJSContextException(aCx);
       return;
     }
   }
 
   JS::Rooted<JSObject*> retval(aCx);
   retval = JS::CallOriginalPromiseThen(aCx, promise, resolveCallback,
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -37,18 +37,16 @@ static const char16_t SEMICOLON    = ';'
 static const char16_t SLASH        = '/';
 static const char16_t PLUS         = '+';
 static const char16_t DASH         = '-';
 static const char16_t DOT          = '.';
 static const char16_t UNDERLINE    = '_';
 static const char16_t TILDE        = '~';
 static const char16_t WILDCARD     = '*';
 static const char16_t SINGLEQUOTE  = '\'';
-static const char16_t OPEN_CURL    = '{';
-static const char16_t CLOSE_CURL   = '}';
 static const char16_t NUMBER_SIGN  = '#';
 static const char16_t QUESTIONMARK = '?';
 static const char16_t PERCENT_SIGN = '%';
 static const char16_t EXCLAMATION  = '!';
 static const char16_t DOLLAR       = '$';
 static const char16_t AMPERSAND    = '&';
 static const char16_t OPENBRACE    = '(';
 static const char16_t CLOSINGBRACE = ')';
@@ -521,36 +519,16 @@ nsCSPParser::host()
     logWarningErrorToConsole(nsIScriptError::warningFlag, "hostNameMightBeKeyword",
                              params, ArrayLength(params));
   }
 
   // Create a new nsCSPHostSrc with the parsed host.
   return new nsCSPHostSrc(mCurValue);
 }
 
-// apps use special hosts; "app://{app-host-is-uid}""
-nsCSPHostSrc*
-nsCSPParser::appHost()
-{
-  CSPPARSERLOG(("nsCSPParser::appHost, mCurToken: %s, mCurValue: %s",
-               NS_ConvertUTF16toUTF8(mCurToken).get(),
-               NS_ConvertUTF16toUTF8(mCurValue).get()));
-
-  while (hostChar()) { /* consume */ }
-
-  // appHosts have to end with "}", otherwise we have to report an error
-  if (!accept(CLOSE_CURL)) {
-    const char16_t* params[] = { mCurToken.get() };
-    logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
-                             params, ArrayLength(params));
-    return nullptr;
-  }
-  return new nsCSPHostSrc(mCurValue);
-}
-
 // keyword-source = "'self'" / "'unsafe-inline'" / "'unsafe-eval'"
 nsCSPBaseSrc*
 nsCSPParser::keywordSource()
 {
   CSPPARSERLOG(("nsCSPParser::keywordSource, mCurToken: %s, mCurValue: %s",
                NS_ConvertUTF16toUTF8(mCurToken).get(),
                NS_ConvertUTF16toUTF8(mCurValue).get()));
 
@@ -610,23 +588,16 @@ nsCSPParser::keywordSource()
 // host-source = [ scheme "://" ] host [ port ] [ path ]
 nsCSPHostSrc*
 nsCSPParser::hostSource()
 {
   CSPPARSERLOG(("nsCSPParser::hostSource, mCurToken: %s, mCurValue: %s",
                NS_ConvertUTF16toUTF8(mCurToken).get(),
                NS_ConvertUTF16toUTF8(mCurValue).get()));
 
-  // Special case handling for app specific hosts
-  if (accept(OPEN_CURL)) {
-    // If appHost() returns null, the error was handled in appHost().
-    // appHosts can not have a port, or path, we can return.
-    return appHost();
-  }
-
   nsCSPHostSrc* cspHost = host();
   if (!cspHost) {
     // Error was reported in host()
     return nullptr;
   }
 
   // Calling port() to see if there is a port to parse, if an error
   // occurs, port() reports the error, if port() returns true;
--- a/dom/security/nsCSPParser.h
+++ b/dom/security/nsCSPParser.h
@@ -128,17 +128,16 @@ class nsCSPParser {
     void                sandboxFlagList(nsCSPDirective* aDir);
     void                sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs);
     nsCSPBaseSrc*       sourceExpression();
     nsCSPSchemeSrc*     schemeSource();
     nsCSPHostSrc*       hostSource();
     nsCSPBaseSrc*       keywordSource();
     nsCSPNonceSrc*      nonceSource();
     nsCSPHashSrc*       hashSource();
-    nsCSPHostSrc*       appHost(); // helper function to support app specific hosts
     nsCSPHostSrc*       host();
     bool                hostChar();
     bool                schemeChar();
     bool                port();
     bool                path(nsCSPHostSrc* aCspHost);
 
     bool subHost();                                         // helper function to parse subDomains
     bool atValidUnreservedChar();                           // helper function to parse unreserved
--- a/dom/security/test/gtest/TestCSPParser.cpp
+++ b/dom/security/test/gtest/TestCSPParser.cpp
@@ -457,18 +457,16 @@ TEST(CSPParser, SimplePolicies)
     { "object-src media1.example.com media2.example.com *.cdn.example.com;",
       "object-src http://media1.example.com http://media2.example.com http://*.cdn.example.com" },
     { "script-src trustedscripts.example.com",
       "script-src http://trustedscripts.example.com" },
     { "script-src 'self' ; default-src trustedscripts.example.com",
       "script-src http://www.selfuri.com; default-src http://trustedscripts.example.com" },
     { "default-src 'none'; report-uri http://localhost:49938/test",
       "default-src 'none'; report-uri http://localhost:49938/test" },
-    { "default-src app://{app-host-is-uid}",
-      "default-src app://{app-host-is-uid}" },
     { "   ;   default-src abc",
       "default-src http://abc" },
     { " ; ; ; ;     default-src            abc    ; ; ; ;",
       "default-src http://abc" },
     { "script-src 'none' 'none' 'none';",
       "script-src 'none'" },
     { "script-src http://www.example.com/path-1//",
       "script-src http://www.example.com/path-1//" },
@@ -628,18 +626,16 @@ TEST(CSPParser, GoodGeneratedPolicies)
     { "media-src foo.bar",
       "media-src http://foo.bar" },
     { "frame-src *.bar",
       "frame-src http://*.bar" },
     { "font-src com",
       "font-src http://com" },
     { "connect-src f00b4r.com",
       "connect-src http://f00b4r.com" },
-    { "default-src {app-url-is-uid}",
-      "default-src http://{app-url-is-uid}" },
     { "script-src *.a.b.c",
       "script-src http://*.a.b.c" },
     { "object-src *.b.c",
       "object-src http://*.b.c" },
     { "style-src a.b.c",
       "style-src http://a.b.c" },
     { "img-src a.com",
       "img-src http://a.com" },
@@ -654,32 +650,26 @@ TEST(CSPParser, GoodGeneratedPolicies)
     { "default-src a.com:23",
       "default-src http://a.com:23" },
     { "script-src https://a.com:200",
       "script-src https://a.com:200" },
     { "object-src data:",
       "object-src data:" },
     { "style-src javascript:",
       "style-src javascript:" },
-    { "img-src {app-host-is-uid}",
-      "img-src http://{app-host-is-uid}" },
-    { "media-src app://{app-host-is-uid}",
-      "media-src app://{app-host-is-uid}" },
     { "frame-src https://foobar.com:443",
       "frame-src https://foobar.com:443" },
     { "font-src https://a.com:443",
       "font-src https://a.com:443" },
     { "connect-src http://a.com:80",
       "connect-src http://a.com:80" },
     { "default-src http://foobar.com",
       "default-src http://foobar.com" },
     { "script-src https://foobar.com",
       "script-src https://foobar.com" },
-    { "object-src https://{app-host-is-uid}",
-      "object-src https://{app-host-is-uid}" },
     { "style-src 'none'",
       "style-src 'none'" },
     { "img-src foo.bar:21 https://ras.bar",
       "img-src http://foo.bar:21 https://ras.bar" },
     { "media-src http://foo.bar:21 https://ras.bar:443",
       "media-src http://foo.bar:21 https://ras.bar:443" },
     { "frame-src http://self.com:80",
       "frame-src http://self.com:80" },
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -230,18 +230,16 @@ NS_INTERFACE_MAP_BEGIN(ServiceWorkerMana
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIServiceWorkerManager)
 NS_INTERFACE_MAP_END
 
 ServiceWorkerManager::ServiceWorkerManager()
   : mActor(nullptr)
   , mShuttingDown(false)
 {
-  // Register this component to PBackground.
-  MOZ_ALWAYS_TRUE(BackgroundChild::GetOrCreateForCurrentThread(this));
 }
 
 ServiceWorkerManager::~ServiceWorkerManager()
 {
   // The map will assert if it is not empty when destroyed.
   mRegistrationInfos.Clear();
   MOZ_ASSERT(!mActor);
 }
@@ -268,16 +266,22 @@ ServiceWorkerManager::Init(ServiceWorker
       rv = obs->AddObserver(this, PURGE_SESSION_HISTORY, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, PURGE_DOMAIN_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, CLEAR_ORIGIN_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
+
+  if (!BackgroundChild::GetOrCreateForCurrentThread(this)) {
+    // Make sure to do this last as our failure cleanup expects Init() to have
+    // executed.
+    ActorFailed();
+  }
 }
 
 void
 ServiceWorkerManager::MaybeStartShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1230,17 +1230,17 @@ private:
   {
     // Silence bad assertions.
   }
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
-    JS::Rooted<JS::Value> callable(aCx, JS::ObjectValue(*mHandler->Callable()));
+    JS::Rooted<JS::Value> callable(aCx, JS::ObjectOrNullValue(mHandler->CallableOrNull()));
     JS::HandleValueArray args = JS::HandleValueArray::empty();
     JS::Rooted<JS::Value> rval(aCx);
     if (!JS_CallFunctionValue(aCx, global, callable, args, &rval)) {
       // Just return false; WorkerRunnable::Run will report the exception.
       return false;
     }
 
     return true;
--- a/dom/xhr/XMLHttpRequest.h
+++ b/dom/xhr/XMLHttpRequest.h
@@ -13,16 +13,17 @@
 #include "nsIXMLHttpRequest.h"
 
 class nsIJSID;
 
 namespace mozilla {
 namespace dom {
 
 class Blob;
+class DOMString;
 class FormData;
 class URLSearchParams;
 class XMLHttpRequestUpload;
 
 class XMLHttpRequest : public XMLHttpRequestEventTarget
 {
 public:
   static already_AddRefed<XMLHttpRequest>
@@ -133,17 +134,17 @@ public:
   SetResponseType(XMLHttpRequestResponseType aType,
                   ErrorResult& aRv) = 0;
 
   virtual void
   GetResponse(JSContext* aCx, JS::MutableHandle<JS::Value> aResponse,
               ErrorResult& aRv) = 0;
 
   virtual void
-  GetResponseText(nsAString& aResponseText, ErrorResult& aRv) = 0;
+  GetResponseText(DOMString& aResponseText, ErrorResult& aRv) = 0;
 
   virtual nsIDocument*
   GetResponseXML(ErrorResult& aRv) = 0;
 
   virtual bool
   MozBackgroundRequest() const = 0;
 
   virtual void
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -9,16 +9,17 @@
 #include <algorithm>
 #ifndef XP_WIN
 #include <unistd.h>
 #endif
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/BlobSet.h"
 #include "mozilla/dom/DocGroup.h"
+#include "mozilla/dom/DOMString.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/MutableBlobStorage.h"
 #include "mozilla/dom/XMLDocument.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
@@ -566,22 +567,28 @@ XMLHttpRequestMainThread::AppendToRespon
   helper.AddLength(destlen);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText)
 {
   ErrorResult rv;
-  GetResponseText(aResponseText, rv);
-  return rv.StealNSResult();
+  DOMString str;
+  GetResponseText(str, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+
+  str.ToString(aResponseText);
+  return NS_OK;
 }
 
 void
-XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
+XMLHttpRequestMainThread::GetResponseText(DOMString& aResponseText,
                                           ErrorResult& aRv)
 {
   XMLHttpRequestStringSnapshot snapshot;
   GetResponseText(snapshot, aRv);
   if (aRv.Failed()) {
     return;
   }
 
@@ -768,18 +775,18 @@ XMLHttpRequestMainThread::GetResponse(JS
                                       JS::MutableHandle<JS::Value> aResponse,
                                       ErrorResult& aRv)
 {
   switch (mResponseType) {
   case XMLHttpRequestResponseType::_empty:
   case XMLHttpRequestResponseType::Text:
   case XMLHttpRequestResponseType::Moz_chunked_text:
   {
-    nsAutoString str;
-    aRv = GetResponseText(str);
+    DOMString str;
+    GetResponseText(str, aRv);
     if (aRv.Failed()) {
       return;
     }
     if (!xpc::StringToJsval(aCx, str, aResponse)) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     }
     return;
   }
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -52,16 +52,17 @@ class nsILoadGroup;
 class nsIUnicodeDecoder;
 class nsIJSID;
 
 namespace mozilla {
 namespace dom {
 
 class Blob;
 class BlobSet;
+class DOMString;
 class FormData;
 class URLSearchParams;
 class XMLHttpRequestUpload;
 struct OriginAttributesDictionary;
 
 // A helper for building up an ArrayBuffer object's data
 // before creating the ArrayBuffer itself.  Will do doubling
 // based reallocation, up to an optional maximum growth given.
@@ -463,17 +464,17 @@ public:
   SetResponseType(XMLHttpRequestResponseType aType,
                   ErrorResult& aRv) override;
 
   virtual void
   GetResponse(JSContext* aCx, JS::MutableHandle<JS::Value> aResponse,
               ErrorResult& aRv) override;
 
   virtual void
-  GetResponseText(nsAString& aResponseText, ErrorResult& aRv) override;
+  GetResponseText(DOMString& aResponseText, ErrorResult& aRv) override;
 
   void
   GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot,
                   ErrorResult& aRv);
 
   virtual nsIDocument*
   GetResponseXML(ErrorResult& aRv) override;
 
--- a/dom/xhr/XMLHttpRequestString.cpp
+++ b/dom/xhr/XMLHttpRequestString.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "XMLHttpRequestString.h"
 #include "mozilla/Mutex.h"
 #include "nsISupportsImpl.h"
+#include "mozilla/dom/DOMString.h"
 
 namespace mozilla {
 namespace dom {
 
 class XMLHttpRequestStringBuffer final
 {
   friend class XMLHttpRequestStringWriterHelper;
   friend class XMLHttpRequestStringSnapshotReaderHelper;
@@ -56,21 +57,34 @@ public:
 
   size_t
   SizeOfThis(MallocSizeOf aMallocSizeOf) const
   {
     return mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   }
 
   MOZ_MUST_USE bool
-  GetAsString(nsAString& aString, uint32_t aLength)
+  GetAsString(DOMString& aString, uint32_t aLength)
   {
     MutexAutoLock lock(mMutex);
     MOZ_ASSERT(aLength <= mData.Length());
-    return aString.Assign(mData, aLength, mozilla::fallible);
+    nsStringBuffer* buf = nsStringBuffer::FromString(mData);
+    if (buf) {
+      // We have to use SetEphemeralStringBuffer, because once we release our
+      // mutex mData can get mutated from some other thread while the DOMString
+      // is still alive.
+      aString.SetEphemeralStringBuffer(buf, aLength);
+      return true;
+    }
+
+    // We can get here if mData is empty.  In that case it won't have an
+    // nsStringBuffer....
+    MOZ_ASSERT(mData.IsEmpty());
+    return aString.AsAString().Assign(mData.BeginReading(), aLength,
+                                      mozilla::fallible);
   }
 
   void
   CreateSnapshot(XMLHttpRequestStringSnapshot& aSnapshot)
   {
     MutexAutoLock lock(mMutex);
     aSnapshot.Set(this, mData.Length());
   }
@@ -182,27 +196,25 @@ XMLHttpRequestStringSnapshot::Set(XMLHtt
   MOZ_ASSERT(aLength <= aBuffer->UnsafeLength());
 
   mBuffer = aBuffer;
   mLength = aLength;
   mVoid = false;
 }
 
 bool
-XMLHttpRequestStringSnapshot::GetAsString(nsAString& aString) const
+XMLHttpRequestStringSnapshot::GetAsString(DOMString& aString) const
 {
   if (mBuffer) {
     MOZ_ASSERT(!mVoid);
     return mBuffer->GetAsString(aString, mLength);
   }
 
-  aString.Truncate();
-
   if (mVoid) {
-    aString.SetIsVoid(true);
+    aString.SetNull();
   }
 
   return true;
 }
 
 // ---------------------------------------------------------------------------
 // XMLHttpRequestStringWriterHelper
 
--- a/dom/xhr/XMLHttpRequestString.h
+++ b/dom/xhr/XMLHttpRequestString.h
@@ -10,16 +10,17 @@
 #include "nsString.h"
 
 namespace mozilla {
 
 class Mutex;
 
 namespace dom {
 
+class DOMString;
 class XMLHttpRequestStringBuffer;
 class XMLHttpRequestStringSnapshot;
 class XMLHttpRequestStringWriterHelper;
 class XMLHttpRequestStringSnapshotReaderHelper;
 
 // We want to avoid the dup of strings when XHR in workers has access to
 // responseText for events dispatched during the loading state. For this reason
 // we use this class, able to create snapshots of the current size of itself
@@ -113,17 +114,17 @@ public:
     return mVoid;
   }
 
   bool IsEmpty() const
   {
     return !mLength;
   }
 
-  MOZ_MUST_USE bool GetAsString(nsAString& aString) const;
+  MOZ_MUST_USE bool GetAsString(DOMString& aString) const;
 
 private:
   XMLHttpRequestStringSnapshot(const XMLHttpRequestStringSnapshot&) = delete;
   XMLHttpRequestStringSnapshot& operator=(const XMLHttpRequestStringSnapshot&&) = delete;
 
   void Set(XMLHttpRequestStringBuffer* aBuffer, uint32_t aLength);
 
   void ResetInternal(bool aIsVoid);
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -2421,17 +2421,17 @@ XMLHttpRequestWorker::GetResponse(JSCont
     }
   }
 
   aRv = mStateData.mResponseResult;
   aResponse.set(mStateData.mResponse);
 }
 
 void
-XMLHttpRequestWorker::GetResponseText(nsAString& aResponseText, ErrorResult& aRv)
+XMLHttpRequestWorker::GetResponseText(DOMString& aResponseText, ErrorResult& aRv)
 {
   aRv = mStateData.mResponseTextResult;
   if (aRv.Failed()) {
     return;
   }
 
   if (!mStateData.mResponseText.GetAsString(aResponseText)) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
--- a/dom/xhr/XMLHttpRequestWorker.h
+++ b/dom/xhr/XMLHttpRequestWorker.h
@@ -12,16 +12,17 @@
 #include "XMLHttpRequestString.h"
 #include "mozilla/dom/TypedArray.h"
 
 namespace mozilla {
 namespace dom {
 
 class Proxy;
 class SendRunnable;
+class DOMString;
 
 namespace workers {
 class WorkerPrivate;
 }
 
 class XMLHttpRequestWorker final : public XMLHttpRequest,
                                    public workers::WorkerHolder
 {
@@ -241,17 +242,17 @@ public:
   SetResponseType(XMLHttpRequestResponseType aResponseType,
                   ErrorResult& aRv) override;
 
   virtual void
   GetResponse(JSContext* /* unused */, JS::MutableHandle<JS::Value> aResponse,
               ErrorResult& aRv) override;
 
   virtual void
-  GetResponseText(nsAString& aResponseText, ErrorResult& aRv) override;
+  GetResponseText(DOMString& aResponseText, ErrorResult& aRv) override;
 
   virtual nsIDocument*
   GetResponseXML(ErrorResult& aRv) override
   {
     MOZ_CRASH("This method should not be called.");
   }
 
   virtual void
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -19,75 +19,75 @@ public:
     gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                bool aNeedsBold);
 
     virtual ~gfxMacFont();
 
     CGFontRef GetCGFontRef() const { return mCGFont; }
 
     /* overrides for the pure virtual methods in gfxFont */
-    virtual uint32_t GetSpaceGlyph() override {
+    uint32_t GetSpaceGlyph() override {
         return mSpaceGlyph;
     }
 
-    virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
+    bool SetupCairoFont(DrawTarget* aDrawTarget) override;
 
     /* override Measure to add padding for antialiasing */
-    virtual RunMetrics Measure(const gfxTextRun *aTextRun,
-                               uint32_t aStart, uint32_t aEnd,
-                               BoundingBoxType aBoundingBoxType,
-                               DrawTarget *aDrawTargetForTightBoundingBox,
-                               Spacing *aSpacing,
-                               uint16_t aOrientation) override;
+    RunMetrics Measure(const gfxTextRun *aTextRun,
+                       uint32_t aStart, uint32_t aEnd,
+                       BoundingBoxType aBoundingBoxType,
+                       DrawTarget *aDrawTargetForTightBoundingBox,
+                       Spacing *aSpacing,
+                       uint16_t aOrientation) override;
 
     // We need to provide hinted (non-linear) glyph widths if using a font
     // with embedded color bitmaps (Apple Color Emoji), as Core Text renders
     // the glyphs with non-linear scaling at small pixel sizes.
-    virtual bool ProvidesGlyphWidths() const override {
+    bool ProvidesGlyphWidths() const override {
         return mVariationFont ||
                mFontEntry->HasFontTable(TRUETYPE_TAG('s','b','i','x'));
     }
 
-    virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget,
-                                  uint16_t aGID) override;
+    int32_t GetGlyphWidth(DrawTarget& aDrawTarget,
+                          uint16_t aGID) override;
 
-    virtual already_AddRefed<mozilla::gfx::ScaledFont>
+    already_AddRefed<mozilla::gfx::ScaledFont>
     GetScaledFont(mozilla::gfx::DrawTarget *aTarget) override;
 
-    virtual already_AddRefed<mozilla::gfx::GlyphRenderingOptions>
+    already_AddRefed<mozilla::gfx::GlyphRenderingOptions>
       GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr) override;
 
-    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontCacheSizes* aSizes) const override;
-    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontCacheSizes* aSizes) const override;
+    void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                FontCacheSizes* aSizes) const override;
+    void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                FontCacheSizes* aSizes) const override;
 
-    virtual FontType GetType() const override { return FONT_TYPE_MAC; }
+    FontType GetType() const override { return FONT_TYPE_MAC; }
 
     // Helper to create a CTFont from a CGFont, with optional font descriptor
     // (for features), and copying any variations that were set on the CGFont.
     // This is public so that gfxCoreTextShaper can also use it.
     static CTFontRef
     CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont,
                                          CGFloat aSize,
                                          CTFontDescriptorRef aFontDesc = nullptr);
 
 protected:
-    virtual const Metrics& GetHorizontalMetrics() override {
+    const Metrics& GetHorizontalMetrics() override {
         return mMetrics;
     }
 
     // override to prefer CoreText shaping with fonts that depend on AAT
-    virtual bool ShapeText(DrawTarget     *aDrawTarget,
-                           const char16_t *aText,
-                           uint32_t        aOffset,
-                           uint32_t        aLength,
-                           Script          aScript,
-                           bool            aVertical,
-                           gfxShapedText  *aShapedText) override;
+    bool ShapeText(DrawTarget     *aDrawTarget,
+                   const char16_t *aText,
+                   uint32_t        aOffset,
+                   uint32_t        aLength,
+                   Script          aScript,
+                   bool            aVertical,
+                   gfxShapedText  *aShapedText) override;
 
     void InitMetrics();
     void InitMetricsFromPlatform();
 
     // Get width and glyph ID for a character; uses aConvFactor
     // to convert font units as returned by CG to actual dimensions
     gfxFloat GetCharWidth(CFDataRef aCmap, char16_t aUniChar,
                           uint32_t *aGlyphID, gfxFloat aConvFactor);
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -36,35 +36,36 @@ public:
     MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef,
                    uint16_t aWeight, uint16_t aStretch, uint8_t aStyle,
                    bool aIsDataUserFont, bool aIsLocal);
 
     virtual ~MacOSFontEntry() {
         ::CGFontRelease(mFontRef);
     }
 
-    virtual CGFontRef GetFontRef();
+    CGFontRef GetFontRef();
 
     // override gfxFontEntry table access function to bypass table cache,
     // use CGFontRef API to get direct access to system font data
-    virtual hb_blob_t *GetFontTable(uint32_t aTag) override;
+    hb_blob_t *GetFontTable(uint32_t aTag) override;
 
-    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontListSizes* aSizes) const override;
+    void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                FontListSizes* aSizes) const override;
 
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
 
     bool RequiresAATLayout() const { return mRequiresAAT; }
 
     bool IsCFF();
 
 protected:
-    virtual gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) override;
+    gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle,
+                                bool aNeedsBold) override;
 
-    virtual bool HasFontTable(uint32_t aTableTag) override;
+    bool HasFontTable(uint32_t aTableTag) override;
 
     static void DestroyBlobFunc(void* aUserData);
 
     CGFontRef mFontRef; // owning reference to the CGFont, released on destruction
 
     double mSizeHint;
 
     bool mFontRefInitialized;
@@ -115,42 +116,43 @@ public:
         kHiddenSystemFontFamily = 1, // hidden system family, not exposed to UI
         kTextSizeSystemFontFamily = 2, // name of 'system' font at text sizes
         kDisplaySizeSystemFontFamily = 3 // 'system' font at display sizes
     };
     void GetSystemFontFamilyList(
         InfallibleTArray<mozilla::dom::FontFamilyListEntry>* aList);
 
 protected:
-    virtual gfxFontFamily*
+    gfxFontFamily*
     GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
 
 private:
     friend class gfxPlatformMac;
 
     gfxMacPlatformFontList();
     virtual ~gfxMacPlatformFontList();
 
     // initialize font lists
-    virtual nsresult InitFontListForPlatform() override;
+    nsresult InitFontListForPlatform() override;
 
     // special case font faces treated as font families (set via prefs)
     void InitSingleFaceList();
 
     // initialize system fonts
     void InitSystemFontNames();
 
     // helper function to lookup in both hidden system fonts and normal fonts
     gfxFontFamily* FindSystemFontFamily(const nsAString& aFamily);
 
-    static void RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
-                                                           void *observer,
-                                                           CFStringRef name,
-                                                           const void *object,
-                                                           CFDictionaryRef userInfo);
+    static void
+    RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
+                                               void *observer,
+                                               CFStringRef name,
+                                               const void *object,
+                                               CFDictionaryRef userInfo);
 
     // search fonts system-wide for a given character, null otherwise
     gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
                                      Script aRunScript,
                                      const gfxFontStyle* aMatchStyle,
                                      uint32_t& aCmapCount,
                                      gfxFontFamily** aMatchedFamily) override;
 
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -1059,17 +1059,17 @@ gfxMacPlatformFontList::GlobalFontFallba
             buffer.SetLength(familyNameLen+1);
             ::CFStringGetCharacters(familyNameRef, ::CFRangeMake(0, familyNameLen),
                                     buffer.Elements());
             buffer[familyNameLen] = 0;
             nsDependentString familyNameString(reinterpret_cast<char16_t*>(buffer.Elements()), familyNameLen);
 
             bool needsBold;  // ignored in the system fallback case
 
-            gfxFontFamily *family = FindFamily(familyNameString);
+            gfxFontFamily *family = FindSystemFontFamily(familyNameString);
             if (family) {
                 fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
                 if (fontEntry) {
                     if (fontEntry->HasCharacter(aCh)) {
                         *aMatchedFamily = family;
                     } else {
                         fontEntry = nullptr;
                         cantUseFallbackFont = true;
--- a/gfx/thebes/gfxScriptItemizer.cpp
+++ b/gfx/thebes/gfxScriptItemizer.cpp
@@ -102,22 +102,27 @@ gfxScriptItemizer::fixup(Script newScrip
     int32_t fixupSP = DEC(parenSP, fixupCount);
 
     while (fixupCount-- > 0) {
         fixupSP = INC1(fixupSP);
         parenStack[fixupSP].scriptCode = newScriptCode;
     }
 }
 
+// We regard the current char as having the same script as the in-progress run
+// if either script code is Common or Inherited, or if the run script appears
+// in the character's ScriptExtensions, or if the char is a cluster extender.
 static inline bool
-SameScript(Script runScript, Script currCharScript)
+SameScript(Script runScript, Script currCharScript, uint32_t aCurrCh)
 {
     return runScript <= Script::INHERITED ||
            currCharScript <= Script::INHERITED ||
-           currCharScript == runScript;
+           currCharScript == runScript ||
+           IsClusterExtender(aCurrCh) ||
+           HasScript(aCurrCh, runScript);
 }
 
 gfxScriptItemizer::gfxScriptItemizer(const char16_t *src, uint32_t length)
     : textPtr(src), textLength(length)
 {
     reset();
 }
 
@@ -189,17 +194,17 @@ gfxScriptItemizer::Next(uint32_t& aRunSt
                 }
 
                 if (STACK_IS_NOT_EMPTY()) {
                     sc = TOP().scriptCode;
                 }
             }
         }
 
-        if (SameScript(scriptCode, sc)) {
+        if (SameScript(scriptCode, sc, ch)) {
             if (scriptCode <= Script::INHERITED &&
                 sc > Script::INHERITED)
             {
                 scriptCode = sc;
                 fixup(scriptCode);
             }
 
             /*
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -314,16 +314,29 @@ gfxUserFontEntry::GetFamilyNameAndURIFor
   aFamilyName.Assign(NS_ConvertUTF16toUTF8(mFamilyName));
 
   aURI.Truncate();
   if (mSrcIndex == mSrcList.Length()) {
     aURI.AppendLiteral("(end of source list)");
   } else {
     if (mSrcList[mSrcIndex].mURI) {
       mSrcList[mSrcIndex].mURI->GetSpec(aURI);
+      // If the source URI was very long, elide the middle of it.
+      // In principle, the byte-oriented chopping here could leave us
+      // with partial UTF-8 characters at the point where we cut it,
+      // but it really doesn't matter as this is just for logging.
+      const uint32_t kMaxURILengthForLogging = 256;
+      // UTF-8 ellipsis, with spaces to allow additional wrap opportunities
+      // in the resulting log message
+      const char kEllipsis[] = { ' ', '\xE2', '\x80', '\xA6', ' ' };
+      if (aURI.Length() > kMaxURILengthForLogging) {
+        aURI.Replace(kMaxURILengthForLogging / 2,
+                     aURI.Length() - kMaxURILengthForLogging,
+                     kEllipsis, ArrayLength(kEllipsis));
+      }
     } else {
       aURI.AppendLiteral("(invalid URI)");
     }
   }
 }
 
 struct WOFFHeader {
     AutoSwap_PRUint32 signature;
--- a/intl/unicharutil/util/nsUnicodeProperties.h
+++ b/intl/unicharutil/util/nsUnicodeProperties.h
@@ -100,16 +100,22 @@ GetLineBreakClass(uint32_t aCh)
 
 inline Script
 GetScriptCode(uint32_t aCh)
 {
   UErrorCode err = U_ZERO_ERROR;
   return Script(uscript_getScript(aCh, &err));
 }
 
+inline bool
+HasScript(uint32_t aCh, Script aScript)
+{
+  return uscript_hasScript(aCh, UScriptCode(aScript));
+}
+
 inline uint32_t
 GetScriptTagForCode(Script aScriptCode)
 {
   const char* tag = uscript_getShortName(UScriptCode(aScriptCode));
   return HB_TAG(tag[0], tag[1], tag[2], tag[3]);
 }
 
 inline PairedBracketType
@@ -184,16 +190,26 @@ uint8_t GetCombiningClass(uint32_t aCh);
 uint8_t GetGeneralCategory(uint32_t aCh);
 
 nsCharType GetBidiCat(uint32_t aCh);
 
 uint8_t GetLineBreakClass(uint32_t aCh);
 
 Script GetScriptCode(uint32_t aCh);
 
+// We don't support ScriptExtensions.txt data when building without ICU.
+// The most important cases will still be handled in gfxScriptItemizer
+// by checking IsClusterExtender to avoid breaking script runs within
+// a cluster.
+inline bool
+HasScript(uint32_t aCh, Script aScript)
+{
+  return false;
+}
+
 uint32_t GetScriptTagForCode(Script aScriptCode);
 
 PairedBracketType GetPairedBracketType(uint32_t aCh);
 uint32_t GetPairedBracket(uint32_t aCh);
 
 /**
  * Return the numeric value of the character. The value returned is the value
  * of the Numeric_Value in field 7 of the UCD, or -1 if field 7 is empty.
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -458,18 +458,20 @@ wasmValidateText('(module (import $bar "
 
 // ----------------------------------------------------------------------------
 // select
 
 wasmFailValidateText('(module (func (select (i32.const 0) (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
 
 wasmFailValidateText('(module (func (select (i32.const 0) (f32.const 0) (i32.const 0))) (export "" 0))', /select operand types must match/);
 wasmFailValidateText('(module (func (select (block ) (i32.const 0) (i32.const 0))) (export "" 0))', /popping value from empty stack/);
-assertEq(wasmEvalText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))').exports[""](), undefined);
-assertEq(wasmEvalText('(module (func (i32.add (i32.const 0) (select (return) (i32.const 0) (i32.const 0)))) (export "" 0))').exports[""](), undefined);
+wasmFailValidateText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))', /non-fallthrough instruction must be followed by end or else/);
+wasmFailValidateText('(module (func (i32.add (i32.const 0) (select (return) (i32.const 0) (i32.const 0)))) (export "" 0))', /non-fallthrough instruction must be followed by end or else/);
+assertEq(wasmEvalText('(module (func (select (block (return)) (i32.const 0) (i32.const 0))) (export "" 0))').exports[""](), undefined);
+assertEq(wasmEvalText('(module (func (i32.add (i32.const 0) (select (block (return)) (i32.const 0) (i32.const 0)))) (export "" 0))').exports[""](), undefined);
 wasmFailValidateText('(module (func (select (if i32 (i32.const 1) (i32.const 0) (f32.const 0)) (i32.const 0) (i32.const 0))) (export "" 0))', mismatchError("f32", "i32"));
 wasmFailValidateText('(module (func) (func (select (call 0) (call 0) (i32.const 0))) (export "" 0))', /popping value from empty stack/);
 
 (function testSideEffects() {
 
 var numT = 0;
 var numF = 0;
 
--- a/js/src/jit-test/tests/wasm/control-flow.js
+++ b/js/src/jit-test/tests/wasm/control-flow.js
@@ -165,17 +165,18 @@ wasmFailValidateText('(module (func (if 
 wasmFailValidateText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/);
 wasmEvalText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if (i32.const 1) (drop (i32.const 1))))))');
 
 // ----------------------------------------------------------------------------
 // return
 
 wasmFullPass('(module (func (return)) (export "run" 0))', undefined);
 wasmFullPass('(module (func (result i32) (return (i32.const 1))) (export "run" 0))', 1);
-wasmFullPass('(module (func (if (return) (i32.const 0))) (export "run" 0))', undefined);
+wasmFailValidateText('(module (func (if (return) (i32.const 0))) (export "run" 0))', /non-fallthrough instruction must be followed by end or else/);
+wasmFullPass('(module (func (if (block (return)) (i32.const 0))) (export "run" 0))', undefined);
 wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', /popping value from empty stack/);
 wasmFullPass('(module (func (return (i32.const 1))) (export "run" 0))', undefined);
 wasmFailValidateText('(module (func (result f32) (return (i32.const 1))) (export "" 0))', mismatchError("i32", "f32"));
 wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', /popping value from empty stack/);
 
 // ----------------------------------------------------------------------------
 // br / br_if
 
@@ -199,88 +200,152 @@ wasmFailValidateText('(module (func (loo
 wasmFailValidateText(`(module (func (result i32)
   (block
     (if
       (br 0)
       (i32.const 0)
       (i32.const 2)
     )
   )
+) (export "" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFailValidateText(`(module (func (result i32)
+  (block
+    (if
+      (block i32 (br 1))
+      (i32.const 0)
+      (i32.const 2)
+    )
+  )
 ) (export "" 0))`, mismatchError("void", "i32"));
 
-wasmFullPass(`(module (func (block $out (br_if $out (br 0)))) (export "run" 0))`, undefined);
+wasmFailValidateText(`(module (func (block $out (br_if $out (br 0)))) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+wasmFullPass(`(module (func (block $out (br_if $out (block i32 (br 1))))) (export "run" 0))`, undefined);
 
 wasmFullPass('(module (func (br 0)) (export "run" 0))', undefined);
 wasmFullPass('(module (func (block (br 0))) (export "run" 0))', undefined);
 wasmFullPass('(module (func (block $l (br $l))) (export "run" 0))', undefined);
 
 wasmFullPass('(module (func (block (block (br 1)))) (export "run" 0))', undefined);
 wasmFullPass('(module (func (block $l (block (br $l)))) (export "run" 0))', undefined);
 
 wasmFullPass('(module (func (block $l (block $m (br $l)))) (export "run" 0))', undefined);
 wasmFullPass('(module (func (block $l (block $m (br $m)))) (export "run" 0))', undefined);
 
-wasmFullPass(`(module (func (result i32)
+wasmFailValidateText(`(module (func (result i32)
   (block
     (br 0)
     (return (i32.const 0))
   )
   (return (i32.const 1))
+) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFullPass(`(module (func (result i32)
+  (block
+    (block (br 1))
+    (return (i32.const 0))
+  )
+  (return (i32.const 1))
 ) (export "run" 0))`, 1);
 
-wasmFullPass(`(module (func (result i32)
+wasmFailValidateText(`(module (func (result i32)
   (block
     (block
       (br 0)
       (return (i32.const 0))
     )
     (return (i32.const 1))
   )
   (return (i32.const 2))
+) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFullPass(`(module (func (result i32)
+  (block
+    (block
+      (block (br 1))
+      (return (i32.const 0))
+    )
+    (return (i32.const 1))
+  )
+  (return (i32.const 2))
 ) (export "run" 0))`, 1);
 
+wasmFailValidateText(`(module (func (result i32)
+  (block $outer
+    (block $inner
+      (br $inner)
+      (return (i32.const 0))
+    )
+    (return (i32.const 1))
+  )
+  (return (i32.const 2))
+) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
 wasmFullPass(`(module (func (result i32)
   (block $outer
     (block $inner
-      (br $inner)
+      (block (br $inner))
       (return (i32.const 0))
     )
     (return (i32.const 1))
   )
   (return (i32.const 2))
 ) (export "run" 0))`, 1);
 
 var notcalled = false;
 var called = false;
 var imports = {"": {
     notcalled() {notcalled = true},
     called() {called = true}
 }};
-wasmFullPass(`(module
+wasmFailValidateText(`(module
 (import "" "notcalled")
 (import "" "called")
 (func
   (block
     (return (br 0))
     (call 0)
   )
   (call 1)
+) (export "run" 2))`, /non-fallthrough instruction must be followed by end or else/);
+wasmFullPass(`(module
+(import "" "notcalled")
+(import "" "called")
+(func
+  (block
+    (block (return (block (br 2))))
+    (call 0)
+  )
+  (call 1)
 ) (export "run" 2))`, undefined, imports);
 assertEq(notcalled, false);
 assertEq(called, true);
 
-wasmFullPass(`(module (func
+wasmFailValidateText(`(module (func
   (block
     (i32.add
       (i32.const 0)
       (return (br 0))
     )
   )
   (return)
+) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+/* TODO: This triggers a bug in BinaryToAST. */
+/*
+wasmFullPass(`(module (func
+  (block
+    (i32.add
+      (i32.const 0)
+      (block i32 (return (block (br 2))))
+    )
+  )
+  (return)
 ) (export "run" 0))`, undefined);
+*/
 
 wasmFullPass(`(module (func (result i32)
   (block
     (if
       (i32.const 1)
       (br 0)
       (return (i32.const 0))
     )
@@ -311,18 +376,20 @@ assertEq(isNonZero(-1), 1);
 wasmFailValidateText('(module (func (result i32) (br 0)))', /popping value from empty stack/);
 wasmFailValidateText('(module (func (result i32) (br 0 (f32.const 42))))', mismatchError("f32", "i32"));
 wasmFailValidateText('(module (func (result i32) (block (br 0))))', mismatchError("void", "i32"));
 wasmFailValidateText('(module (func (result i32) (block f32 (br 0 (f32.const 42)))))', mismatchError("f32", "i32"));
 
 wasmFailValidateText(`(module (func (result i32) (param i32) (block (if i32 (get_local 0) (br 0 (i32.const 42))))) (export "" 0))`, /if without else with a result value/);
 wasmFailValidateText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (drop (i32.const 42))) (br 0 (f32.const 42)))) (export "" 0))`, mismatchError("f32", "i32"));
 
-wasmFullPass('(module (func (result i32) (br 0 (i32.const 42)) (i32.const 13)) (export "run" 0))', 42);
-wasmFullPass('(module (func (result i32) (block i32 (br 0 (i32.const 42)) (i32.const 13))) (export "run" 0))', 42);
+wasmFailValidateText('(module (func (result i32) (br 0 (i32.const 42)) (i32.const 13)) (export "run" 0))', /non-fallthrough instruction must be followed by end or else/);
+wasmFailValidateText('(module (func (result i32) (block i32 (br 0 (i32.const 42)) (i32.const 13))) (export "run" 0))', /non-fallthrough instruction must be followed by end or else/);
+wasmFullPass('(module (func (result i32) (block (br 1 (i32.const 42))) (i32.const 13)) (export "run" 0))', 42);
+wasmFullPass('(module (func (result i32) (block i32 (block (br 1 (i32.const 42))) (i32.const 13))) (export "run" 0))', 42);
 
 wasmFailValidateText('(module (func) (func (block i32 (br 0 (call 0)) (i32.const 13))) (export "" 0))', /popping value from empty stack/);
 wasmFailValidateText('(module (func) (func (block i32 (br_if 0 (call 0) (i32.const 1)) (i32.const 13))) (export "" 0))', /popping value from empty stack/);
 
 var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (drop (i32.const 42))) (i32.const 43))) (export "" 0))`).exports[""];
 assertEq(f(0), 43);
 assertEq(f(1), 43);
 
@@ -371,19 +438,22 @@ assertEq(f(0), 0);
 assertEq(f(1), 100);
 
 wasmFailValidateText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (br_if 0 (i32.const 99) (get_local 0)) (i32.const -1)))) (export "" 0))`, /unused values not explicitly dropped by end of block/);
 
 var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block i32 (drop (br_if 0 (i32.const 99) (get_local 0))) (i32.const -1)))) (export "" 0))`).exports[""];
 assertEq(f(0), 0);
 assertEq(f(1), 100);
 
-wasmFullPass(`(module (func (result i32) (block i32 (br 0 (return (i32.const 42))) (i32.const 0))) (export "run" 0))`, 42);
-wasmFullPass(`(module (func (result i32) (block i32 (return (br 0 (i32.const 42))))) (export "run" 0))`, 42);
-wasmFullPass(`(module (func (result i32) (block i32 (return (br 0 (i32.const 42))) (i32.const 0))) (export "run" 0))`, 42);
+wasmFailValidateText(`(module (func (result i32) (block i32 (br 0 (return (i32.const 42))) (i32.const 0))) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+wasmFailValidateText(`(module (func (result i32) (block i32 (return (br 0 (i32.const 42))))) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+wasmFailValidateText(`(module (func (result i32) (block i32 (return (br 0 (i32.const 42))) (i32.const 0))) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+wasmFullPass(`(module (func (result i32) (block i32 (block (br 1 (block (return (i32.const 42))))) (i32.const 0))) (export "run" 0))`, 42);
+wasmFullPass(`(module (func (result i32) (block i32 (return (block (br 1 (i32.const 42)))))) (export "run" 0))`, 42);
+wasmFullPass(`(module (func (result i32) (block i32 (block (return (block (br 2 (i32.const 42))))) (i32.const 0))) (export "run" 0))`, 42);
 
 wasmFullPass(`(module (func (result f32) (drop (block i32 (br 0 (i32.const 0)))) (block f32 (br 0 (f32.const 42)))) (export "run" 0))`, 42);
 
 var called = 0;
 var imports = {
     sideEffects: {
         ifTrue(x) {assertEq(x, 13); called++;},
         ifFalse(x) {assertEq(x, 37); called--;}
@@ -632,36 +702,63 @@ wasmFailValidateText('(module (func (br_
 wasmFailValidateText('(module (func (br_table 0 1 (i32.const 0))))', DEPTH_OUT_OF_BOUNDS);
 wasmFailValidateText('(module (func (block (br_table 2 0 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS);
 wasmFailValidateText('(module (func (block (br_table 0 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS);
 wasmFailValidateText('(module (func (block (br_table 0 (f32.const 0)))))', mismatchError("f32", "i32"));
 wasmFailValidateText('(module (func (loop (br_table 2 0 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS);
 wasmFailValidateText('(module (func (loop (br_table 0 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS);
 wasmFailValidateText('(module (func (loop (br_table 0 (f32.const 0)))))', mismatchError("f32", "i32"));
 
+wasmFailValidateText(`(module (func (result i32) (param i32)
+  (block $default
+   (br_table $default (get_local 0))
+   (return (i32.const 0))
+  )
+  (return (i32.const 1))
+) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
 wasmFullPass(`(module (func (result i32) (param i32)
   (block $default
-   (br_table $default (get_local 0))
+   (block (br_table $default (get_local 0)))
    (return (i32.const 0))
   )
   (return (i32.const 1))
 ) (export "run" 0))`, 1);
 
-wasmFullPass(`(module (func (result i32) (param i32)
+wasmFailValidateText(`(module (func (result i32) (param i32)
   (block $default
    (br_table $default (return (i32.const 1)))
    (return (i32.const 0))
   )
   (return (i32.const 2))
+) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFullPass(`(module (func (result i32) (param i32)
+  (block $default
+   (block (br_table $default (block i32 (return (i32.const 1)))))
+   (return (i32.const 0))
+  )
+  (return (i32.const 2))
 ) (export "run" 0))`, 1);
 
+wasmFailValidateText(`(module (func (result i32) (param i32)
+  (block $outer
+   (block $inner
+    (br_table $inner (get_local 0))
+    (return (i32.const 0))
+   )
+   (return (i32.const 1))
+  )
+  (return (i32.const 2))
+) (export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
 wasmFullPass(`(module (func (result i32) (param i32)
   (block $outer
    (block $inner
-    (br_table $inner (get_local 0))
+    (block (br_table $inner (get_local 0)))
     (return (i32.const 0))
    )
    (return (i32.const 1))
   )
   (return (i32.const 2))
 ) (export "run" 0))`, 1);
 
 var f = wasmEvalText(`(module (func (result i32) (param i32)
@@ -725,12 +822,16 @@ assertEq(f(2), 9);
 assertEq(f(3), 11);
 assertEq(f(4), 13);
 
 // ----------------------------------------------------------------------------
 // unreachable
 
 const UNREACHABLE = /unreachable/;
 assertErrorMessage(wasmEvalText(`(module (func (unreachable)) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
-assertErrorMessage(wasmEvalText(`(module (func (if (unreachable) (i32.const 0))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
-assertErrorMessage(wasmEvalText(`(module (func (block (br_if 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
-assertErrorMessage(wasmEvalText(`(module (func (block (br_table 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
-assertErrorMessage(wasmEvalText(`(module (func (result i32) (i32.add (i32.const 0) (unreachable))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
+wasmFailValidateText('(module (func (if (unreachable) (i32.const 0))) (export "" 0))', /non-fallthrough instruction must be followed by end or else/);
+wasmFailValidateText('(module (func (block (br_if 0 (unreachable)))) (export "" 0))', /non-fallthrough instruction must be followed by end or else/);
+wasmFailValidateText('(module (func (block (br_table 0 (unreachable)))) (export "" 0))', /non-fallthrough instruction must be followed by end or else/);
+wasmFailValidateText('(module (func (result i32) (i32.add (i32.const 0) (unreachable))) (export "" 0))', /non-fallthrough instruction must be followed by end or else/);
+assertErrorMessage(wasmEvalText(`(module (func (if (block i32 (unreachable)) (i32.const 0))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
+assertErrorMessage(wasmEvalText(`(module (func (block (br_if 0 (block i32 (unreachable))))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
+assertErrorMessage(wasmEvalText(`(module (func (block (br_table 0 (block i32 (unreachable))))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
+assertErrorMessage(wasmEvalText(`(module (func (result i32) (i32.add (i32.const 0) (block i32 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
--- a/js/src/jit-test/tests/wasm/full-cycle.js
+++ b/js/src/jit-test/tests/wasm/full-cycle.js
@@ -1,29 +1,48 @@
 load(libdir + "wasm.js");
 
 wasmFullPass(`(module
     (func $test (result i32) (param i32) (param i32) (i32.add (get_local 0) (get_local 1)))
     (func $run (result i32) (call $test (i32.const 1) (i32.const ${Math.pow(2, 31) - 1})))
     (export "run" $run)
 )`, -Math.pow(2, 31));
 
-wasmFullPass(`(module
+wasmFailValidateText(`(module
     (func (result i32)
         i32.const 1
         i32.const 42
         i32.add
         return
         unreachable
         i32.const 0
         call 3
         i32.const 42
         f32.add
     )
     (func) (func) (func)
+(export "run" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFullPass(`(module
+    (func (result i32)
+        block
+        i32.const 1
+        i32.const 42
+        i32.add
+        return
+        end
+        block
+        unreachable
+        end
+        i32.const 0
+        call 3
+        i32.const 42
+        f32.add
+    )
+    (func) (func) (func)
 (export "run" 0))`, 43);
 
 // Global section.
 wasmFullPass(`(module
  (import $imported "globals" "x" (global i32))
  (global $mut_local (mut i32) (i32.const 0))
  (global $imm_local i32 (i32.const 37))
  (global $imm_local_2 i32 (get_global 0))
--- a/js/src/jit-test/tests/wasm/regress/baseline-joinreg.js
+++ b/js/src/jit-test/tests/wasm/regress/baseline-joinreg.js
@@ -9,10 +9,10 @@ load(libdir + "wasm.js");
 // This test is white-box: it depends on the floating join reg being among the first
 // floating registers to be allocated.
 
 wasmEvalText(`
 (module
  (func $run
   (drop (block f64
    (drop (br_if 0 (f64.const 1) (f64.eq (f64.const 1) (f64.const 0))))
-   (drop (br 0 (f64.const 2))))))
+   (br 0 (f64.const 2)))))
  (export "run" $run))`);
--- a/js/src/jit-test/tests/wasm/regress/misc-control-flow.js
+++ b/js/src/jit-test/tests/wasm/regress/misc-control-flow.js
@@ -19,18 +19,23 @@ wasmFailValidateText(`(module
 )`, mismatchError("void", "i32"));
 
 assertEq(wasmEvalText(`(module
    (func (result i32) (param i32)
      (loop (if (i32.const 0) (br 0))) (get_local 0))
    (export "" 0)
 )`).exports[""](42), 42);
 
+wasmFailValidateText(`(module (func $func$0
+      (block (if (i32.const 1) (loop (br_table 0 (br 0)))))
+  )
+)`, /non-fallthrough instruction must be followed by end or else/);
+
 wasmEvalText(`(module (func $func$0
-      (block (if (i32.const 1) (loop (br_table 0 (br 0)))))
+      (block (if (i32.const 1) (loop (br_table 0 (block i32 (br 1))))))
   )
 )`);
 
 wasmEvalText(`(module (func
       (loop $out $in (br_table $out $out $in (i32.const 0)))
   )
 )`);
 
@@ -48,39 +53,69 @@ wasmEvalText(`(module (func (result i32)
       (i32.const 2)
     )
     (i32.const 3)
     (i32.const 4)
   )
 ))
 `);
 
-wasmEvalText(`(module
+wasmFailValidateText(`(module
   (func (result i32) (param i32) (param i32) (i32.const 0))
   (func (result i32)
    (call 0 (i32.const 1) (call 0 (i32.const 2) (i32.const 3)))
    (call 0 (unreachable) (i32.const 4))
   )
+)`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmEvalText(`(module
+  (func (result i32) (param i32) (param i32) (i32.const 0))
+  (func (result i32)
+   (call 0 (i32.const 1) (call 0 (i32.const 2) (i32.const 3)))
+   (call 0 (block i32 (unreachable)) (i32.const 4))
+  )
 )`);
 
+wasmFailValidateText(`
+(module
+
+ (func
+  (param i32) (param i32) (param i32) (param i32)
+  (result i32)
+  (i32.const 0)
+ )
+
+ (func (result i32)
+  (call 0
+   (i32.const 42)
+   (i32.const 53)
+   (call 0 (i32.const 100) (i32.const 13) (i32.const 37) (i32.const 128))
+   (return (i32.const 42))
+  )
+ )
+
+ (export "" 1)
+)
+`, /non-fallthrough instruction must be followed by end or else/);
+
 wasmEvalText(`
 (module
 
  (func
   (param i32) (param i32) (param i32) (param i32)
   (result i32)
   (i32.const 0)
  )
 
  (func (result i32)
   (call 0
    (i32.const 42)
    (i32.const 53)
    (call 0 (i32.const 100) (i32.const 13) (i32.const 37) (i32.const 128))
-   (return (i32.const 42))
+   (block i32 (return (i32.const 42)))
   )
  )
 
  (export "" 1)
 )
 `).exports[""]();
 
 wasmEvalText(`
@@ -107,27 +142,45 @@ wasmEvalText(`
         },
         two(x, y) {
             assertEq(x, 43);
             assertEq(y, 10);
         }
     }
 }).exports.foo();
 
+wasmFailValidateText(`(module (func
+ (return)
+ (select
+  (loop (i32.const 1))
+  (loop (i32.const 2))
+  (i32.const 3)
+ )
+) (export "" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
 assertEq(wasmEvalText(`(module (func
- (return)
+ (block (return))
  (select
   (loop (i32.const 1))
   (loop (i32.const 2))
   (i32.const 3)
  )
 ) (export "" 0))`).exports[""](), undefined);
 
+wasmFailValidateText(`(module (func (result i32)
+ (return (i32.const 0))
+ (select
+  (loop (i32.const 1))
+  (loop (i32.const 2))
+  (i32.const 3)
+ )
+))`, /non-fallthrough instruction must be followed by end or else/);
+
 wasmEvalText(`(module (func (result i32)
- (return (i32.const 0))
+ (block (return (i32.const 0)))
  (select
   (loop (i32.const 1))
   (loop (i32.const 2))
   (i32.const 3)
  )
 ))`);
 
 wasmEvalText(`(module (func
--- a/js/src/jit-test/tests/wasm/regress/select-any.js
+++ b/js/src/jit-test/tests/wasm/regress/select-any.js
@@ -1,31 +1,45 @@
 load(libdir + "wasm.js");
 
 // Bug 1280921
 
-var m1 = wasmEvalText(
+wasmFailValidateText(
 `(module
   (type $type0 (func))
   (func $func0
    (select (unreachable) (return (nop)) (loop (i32.const 1))))
+  (export "" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFailValidateText(
+`(module
+  (type $type0 (func))
+  (func $func0
+   (select (i32.const 26) (unreachable) (i32.const 3)))
+  (export "" 0))`, /non-fallthrough instruction must be followed by end or else/);
+
+var m3 = wasmEvalText(
+`(module
+  (type $type0 (func))
+  (func $func0
+   (select (block i32 (unreachable)) (block i32 (return (nop))) (loop (i32.const 1))))
   (export "" 0))`).exports[""];
 
 try {
-    m1();
+    m3();
 } catch (e) {
     if (!(e instanceof Error && e.message.match(/unreachable executed/)))
 	throw e;
 }
 
-var m2 = wasmEvalText(
+var m4 = wasmEvalText(
 `(module
   (type $type0 (func))
   (func $func0
-   (select (i32.const 26) (unreachable) (i32.const 3)))
+   (select (i32.const 26) (block i32 (unreachable)) (i32.const 3)))
   (export "" 0))`).exports[""];
 
 try {
-    m2();
+    m4();
 } catch (e) {
     if (!(e instanceof Error && e.message.match(/unreachable executed/)))
 	throw e;
 }
--- a/js/src/jit-test/tests/wasm/spec/block.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/block.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['block.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/br.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/br.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['br.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/br_if.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/br_if.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['br_if.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/br_table.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/br_table.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['br_table.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/func.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/func.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['func.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/labels.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/labels.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['labels.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/loop.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/loop.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['loop.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/return.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/return.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['return.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/select.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/select.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['select.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/unreachable.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/unreachable.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['unreachable.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/unwind.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/unwind.wast.js
@@ -1,1 +1,3 @@
+// TODO: This spec test has instructions between br/etc. and end/etc.
+quit();
 var importedArgs = ['unwind.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/unreachable.js
+++ b/js/src/jit-test/tests/wasm/unreachable.js
@@ -1,30 +1,55 @@
 load(libdir + "wasm.js");
 
 // In unreachable code, the current design is that validation is disabled,
 // meaning we have to have a special mode in the decoder for decoding code
 // that won't actually run.
 
-wasmFullPass(`(module
+wasmFailValidateText(`(module
    (func (result i32)
      (return (i32.const 42))
      (i32.add (f64.const 1.0) (f32.const 0.0))
      (return (f64.const 2.0))
      (if (f32.const 3.0) (i64.const 2) (i32.const 1))
      (select (f64.const -5.0) (f32.const 2.3) (f64.const 8.9))
    )
    (export "run" 0)
+)`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFailValidateText(`(module
+   (func (result i32) (param i32)
+     (block
+        (br_if 1 (i32.const 41) (get_local 0))
+        (br 1 (i32.const 42))
+     )
+     (i32.add (f32.const 0.0) (f64.const 1.0))
+     (return (f64.const 2.0))
+     (if (f32.const 3.0) (i64.const 2) (i32.const 1))
+     (select (f64.const -5.0) (f32.const 2.3) (f64.const 8.9))
+   )
+   (export "run" 0)
+)`, /non-fallthrough instruction must be followed by end or else/);
+
+wasmFullPass(`(module
+   (func (result i32)
+     (block (return (i32.const 42)))
+     (i32.add (f64.const 1.0) (f32.const 0.0))
+     (block (return (f64.const 2.0)))
+     (if (f32.const 3.0) (i64.const 2) (i32.const 1))
+     (select (f64.const -5.0) (f32.const 2.3) (f64.const 8.9))
+   )
+   (export "run" 0)
 )`, 42);
 
 wasmFullPass(`(module
    (func (result i32) (param i32)
      (block
         (br_if 1 (i32.const 41) (get_local 0))
         (br 1 (i32.const 42))
      )
      (i32.add (f32.const 0.0) (f64.const 1.0))
-     (return (f64.const 2.0))
+     (block (return (f64.const 2.0)))
      (if (f32.const 3.0) (i64.const 2) (i32.const 1))
      (select (f64.const -5.0) (f32.const 2.3) (f64.const 8.9))
    )
    (export "run" 0)
 )`, 42, {}, 0);
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -348,21 +348,21 @@ CloseLiveIteratorIon(JSContext* cx, cons
 
     for (unsigned i = 0; i < skipSlots; i++)
         si.skip();
 
     Value v = si.read();
     RootedObject iterObject(cx, &v.toObject());
 
     if (isDestructuring) {
-        Value v = si.read();
-        MOZ_ASSERT(v.isBoolean());
+        RootedValue doneValue(cx, si.read());
+        bool done = ToBoolean(doneValue);
         // Do not call IteratorClose if the destructuring iterator is already
         // done.
-        if (v.isTrue())
+        if (done)
             return;
     }
 
     if (cx->isExceptionPending()) {
         if (tn->kind == JSTRY_FOR_IN)
             UnwindIteratorForException(cx, iterObject);
         else
             IteratorCloseForException(cx, iterObject);
@@ -649,19 +649,19 @@ ProcessTryNotesBaseline(JSContext* cx, c
             }
             break;
           }
 
           case JSTRY_DESTRUCTURING_ITERCLOSE: {
             uint8_t* framePointer;
             uint8_t* stackPointer;
             BaselineFrameAndStackPointersFromTryNote(tn, frame, &framePointer, &stackPointer);
-            Value doneValue(*(reinterpret_cast<Value*>(stackPointer)));
-            MOZ_ASSERT(doneValue.isBoolean());
-            if (doneValue.isFalse()) {
+            RootedValue doneValue(cx, *(reinterpret_cast<Value*>(stackPointer)));
+            bool done = ToBoolean(doneValue);
+            if (!done) {
                 Value iterValue(*(reinterpret_cast<Value*>(stackPointer) + 1));
                 RootedObject iterObject(cx, &iterValue.toObject());
                 if (!IteratorCloseForException(cx, iterObject)) {
                     SettleOnTryNote(cx, tn, frame, ei, rfe, pc);
                     return false;
                 }
             }
             break;
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -995,18 +995,16 @@ AllOnOnePage(uintptr_t start, int size)
     intptr_t start_page = (start & ~CachePage::kPageMask);
     intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
     return start_page == end_page;
 }
 
 static CachePage*
 GetCachePageLocked(Simulator::ICacheMap& i_cache, void* page)
 {
-    MOZ_ASSERT(Simulator::ICacheCheckingEnabled);
-
     Simulator::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
     if (p)
         return p->value();
 
     AutoEnterOOMUnsafeRegion oomUnsafe;
     CachePage* new_page = js_new<CachePage>();
     if (!new_page || !i_cache.add(p, page, new_page))
         oomUnsafe.crash("Simulator CachePage");
--- a/js/src/tests/ecma_6/Destructuring/array-iterator-close.js
+++ b/js/src/tests/ecma_6/Destructuring/array-iterator-close.js
@@ -38,16 +38,32 @@ function test() {
     function throwlhs() {
         throw "in lhs";
     }
     assertThrowsValue(function() {
         0, [...{}[throwlhs()]] = iterable;
     }, "in lhs");
     assertEq(returnCalled, ++returnCalledExpected);
 
+    // throw in lhs ref calls IteratorClose with falsy "done".
+    iterable[Symbol.iterator] = makeIterator({
+        next: function() {
+            // "done" is undefined.
+            return {};
+        },
+        ret: function() {
+            returnCalled++;
+            return {};
+        }
+    });
+    assertThrowsValue(function() {
+        0, [...{}[throwlhs()]] = iterable;
+    }, "in lhs");
+    assertEq(returnCalled, ++returnCalledExpected);
+
     // throw in iter.next doesn't call IteratorClose
     iterable[Symbol.iterator] = makeIterator({
         next: function() {
             throw "in next";
         },
         ret: function() {
             returnCalled++;
             return {};
--- a/js/src/tests/js1_8_5/reflect-parse/Match.js
+++ b/js/src/tests/js1_8_5/reflect-parse/Match.js
@@ -68,16 +68,17 @@ var Match =
         }
     };
 
     function isAtom(x) {
         return (typeof x === "number") ||
             (typeof x === "string") ||
             (typeof x === "boolean") ||
             (x === null) ||
+            (x === undefined) ||
             (typeof x === "object" && x instanceof RegExp);
     }
 
     function isObject(x) {
         return (x !== null) && (typeof x === "object");
     }
 
     function isFunction(x) {
@@ -104,16 +105,17 @@ var Match =
         if (exp instanceof RegExp) {
             if (!(act instanceof RegExp) || exp.source !== act.source)
                 throw new MatchError("expected " + quote(exp) + ", got: " + quote(act));
             return true;
         }
 
         switch (typeof exp) {
         case "string":
+        case "undefined":
             if (act !== exp)
                 throw new MatchError("expected " + quote(exp) + ", got " + quote(act));
             return true;
         case "boolean":
         case "number":
             if (exp !== act)
                 throw new MatchError("expected " + exp + ", got " + quote(act));
             return true;
--- a/js/src/tests/js1_8_5/reflect-parse/declarations.js
+++ b/js/src/tests/js1_8_5/reflect-parse/declarations.js
@@ -73,17 +73,17 @@ assertStmt("function f() { var x = 42; v
 
 assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([assignProp("x", ident("y"))]),
                                           init: ident("foo") }]));
 assertDecl("var {x} = foo;", varDecl([{ id: objPatt([assignProp("x")]),
                                         init: ident("foo") }]));
 
 // Bug 632030: redeclarations between var and funargs, var and function
 assertStmt("function g(x) { var x }",
-           funDecl(ident("g"), [ident("x")], blockStmt([varDecl[{ id: ident("x"), init: null }]])));
+           funDecl(ident("g"), [ident("x")], blockStmt([varDecl([{ id: ident("x"), init: null }])])));
 assertProg("f.p = 1; var f; f.p; function f(){}",
            [exprStmt(aExpr("=", dotExpr(ident("f"), ident("p")), lit(1))),
             varDecl([{ id: ident("f"), init: null }]),
             exprStmt(dotExpr(ident("f"), ident("p"))),
             funDecl(ident("f"), [], blockStmt([]))]);
 }
 
 assertBlockStmt("{ function f(x) {} }",
--- a/js/src/tests/js1_8_5/reflect-parse/destructuring-function-parameters.js
+++ b/js/src/tests/js1_8_5/reflect-parse/destructuring-function-parameters.js
@@ -11,17 +11,17 @@ function testParamPatternCombinations(ma
         function makeSrc(body) {
             return "(function(" + pattSrcs[i].join(",") + ") " + body + ")";
         }
         function makePatt(body) {
             return funExpr(null, pattPatts[i], body);
         }
 
         // no upvars, block body
-        assertExpr(makeSrc("{ }", makePatt(blockStmt([]))));
+        assertExpr(makeSrc("{ }"), makePatt(blockStmt([])));
         // upvars, block body
         assertExpr(makeSrc("{ return [x1,x2,x3,x4,x5]; }"),
                    makePatt(blockStmt([returnStmt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")]))])));
         if (JS_HAS_EXPR_CLOSURES) {
             // no upvars, expression body
             assertExpr(makeSrc("(0)"), makePatt(lit(0)));
             // upvars, expression body
             assertExpr(makeSrc("[x1,x2,x3,x4,x5]"),
--- a/js/src/tests/js1_8_5/reflect-parse/expressionClosures.js
+++ b/js/src/tests/js1_8_5/reflect-parse/expressionClosures.js
@@ -1,11 +1,11 @@
 // |reftest| skip-if(!xulRuntime.shell)
 function test() {
 
 // expression closures
 
 assertDecl("function inc(x) (x + 1)", funDecl(ident("inc"), [ident("x")], binExpr("+", ident("x"), lit(1))));
-assertExpr("(function(x) (x+1))", funExpr(null, [ident("x")], binExpr("+"), ident("x"), lit(1)));
+assertExpr("(function(x) (x+1))", funExpr(null, [ident("x")], binExpr("+", ident("x"), lit(1))));
 
 }
 
 runtest(test);
--- a/js/src/tests/js1_8_5/reflect-parse/statements.js
+++ b/js/src/tests/js1_8_5/reflect-parse/statements.js
@@ -1,21 +1,21 @@
 // |reftest| skip-if(!xulRuntime.shell)
 function test() {
 
 // statements
 
 assertStmt("throw 42", throwStmt(lit(42)));
 assertStmt("for (;;) break", forStmt(null, null, null, breakStmt(null)));
 assertStmt("for (x; y; z) break", forStmt(ident("x"), ident("y"), ident("z"), breakStmt(null)));
-assertStmt("for (var x; y; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), ident("z")));
-assertStmt("for (var x = 42; y; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), ident("z")));
+assertStmt("for (var x; y; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), ident("z"), breakStmt(null)));
+assertStmt("for (var x = 42; y; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), ident("z"), breakStmt(null)));
 assertStmt("for (x; ; z) break", forStmt(ident("x"), null, ident("z"), breakStmt(null)));
-assertStmt("for (var x; ; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), null, ident("z")));
-assertStmt("for (var x = 42; ; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), null, ident("z")));
+assertStmt("for (var x; ; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), null, ident("z"), breakStmt(null)));
+assertStmt("for (var x = 42; ; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), null, ident("z"), breakStmt(null)));
 assertStmt("for (x; y; ) break", forStmt(ident("x"), ident("y"), null, breakStmt(null)));
 assertStmt("for (var x; y; ) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), null, breakStmt(null)));
 assertStmt("for (var x = 42; y; ) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), null, breakStmt(null)));
 assertStmt("for (var x in y) break", forInStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), breakStmt(null)));
 assertStmt("for (x in y) break", forInStmt(ident("x"), ident("y"), breakStmt(null)));
 assertStmt("{ }", blockStmt([]));
 assertStmt("{ throw 1; throw 2; throw 3; }", blockStmt([ throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]));
 assertStmt(";", emptyStmt);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1206,18 +1206,19 @@ ProcessTryNotes(JSContext* cx, Environme
             break;
           }
 
           case JSTRY_DESTRUCTURING_ITERCLOSE: {
             // Whether the destructuring iterator is done is at the top of the
             // stack. The iterator object is second from the top.
             MOZ_ASSERT(tn->stackDepth > 1);
             Value* sp = regs.spForStackDepth(tn->stackDepth);
-            MOZ_ASSERT(sp[-1].isBoolean());
-            if (sp[-1].isFalse()) {
+            RootedValue doneValue(cx, sp[-1]);
+            bool done = ToBoolean(doneValue);
+            if (!done) {
                 RootedObject iterObject(cx, &sp[-2].toObject());
                 if (!IteratorCloseForException(cx, iterObject)) {
                     SettleOnTryNote(cx, tn, ei, regs);
                     return ErrorReturnContinuation;
                 }
             }
             break;
           }
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -118,41 +118,24 @@ using mozilla::IsPowerOfTwo;
 using mozilla::SpecificNaN;
 
 namespace js {
 namespace wasm {
 
 using namespace js::jit;
 using JS::GenericNaN;
 
-struct BaseCompilePolicy : OpIterPolicy
-{
-    static const bool Output = true;
-
-    // The baseline compiler tracks values on a stack of its own -- it
-    // needs to scan that stack for spilling -- and thus has no need
-    // for the values maintained by the iterator.
-    //
-    // The baseline compiler tracks control items on a stack of its
-    // own as well.
-    //
-    // TODO / REDUNDANT (Bug 1316814): It would be nice if we could
-    // make use of the iterator's ControlItems and not require our own
-    // stack for that.
-};
-
-typedef OpIter<BaseCompilePolicy> BaseOpIter;
-
+typedef bool HandleNaNSpecially;
+typedef bool InvertBranch;
+typedef bool IsKnownNotZero;
+typedef bool IsSigned;
 typedef bool IsUnsigned;
-typedef bool IsSigned;
+typedef bool PopStack;
 typedef bool ZeroOnOverflow;
-typedef bool IsKnownNotZero;
-typedef bool HandleNaNSpecially;
-typedef bool PopStack;
-typedef bool InvertBranch;
+
 typedef unsigned ByteSize;
 typedef unsigned BitSize;
 
 // UseABI::Wasm implies that the Tls/Heap/Global registers are nonvolatile,
 // except when InterModule::True is also set, when they are volatile.
 //
 // UseABI::System implies that the Tls/Heap/Global registers are volatile.
 // Additionally, the parameter passing mechanism may be slightly different from
@@ -283,36 +266,17 @@ class BaseCompiler
       public:
         ScratchI32(BaseCompiler& bc) {}
         operator Register() const {
             MOZ_CRASH("BaseCompiler platform hook - ScratchI32");
         }
     };
 #endif
 
-    // A Label in the code, allocated out of a temp pool in the
-    // TempAllocator attached to the compilation.
-
-    struct PooledLabel : public Label, public TempObject, public InlineListNode<PooledLabel>
-    {
-        PooledLabel() : f(nullptr) {}
-        explicit PooledLabel(BaseCompiler* f) : f(f) {}
-        BaseCompiler* f;
-    };
-
-    typedef Vector<PooledLabel*, 8, SystemAllocPolicy> LabelVector;
-
-    struct UniquePooledLabelFreePolicy
-    {
-        void operator()(PooledLabel* p) {
-            p->f->freeLabel(p);
-        }
-    };
-
-    typedef UniquePtr<PooledLabel, UniquePooledLabelFreePolicy> UniquePooledLabel;
+    typedef Vector<NonAssertingLabel, 8, SystemAllocPolicy> LabelVector;
 
     // The strongly typed register wrappers have saved my bacon a few
     // times; though they are largely redundant they stay, for now.
 
     struct RegI32 : public Register
     {
         RegI32() : Register(Register::Invalid()) {}
         explicit RegI32(Register reg) : Register(reg) {}
@@ -406,33 +370,46 @@ class BaseCompiler
         MIRType type() const { MOZ_ASSERT(type_ != MIRType::None); return type_; }
         uint32_t offs() const { MOZ_ASSERT(offs_ != UINT32_MAX); return offs_; }
     };
 
     // Control node, representing labels and stack heights at join points.
 
     struct Control
     {
-        Control(uint32_t framePushed, uint32_t stackSize)
-            : label(nullptr),
-              otherLabel(nullptr),
-              framePushed(framePushed),
-              stackSize(stackSize),
+        Control()
+            : framePushed(UINT32_MAX),
+              stackSize(UINT32_MAX),
               deadOnArrival(false),
               deadThenBranch(false)
         {}
 
-        PooledLabel* label;
-        PooledLabel* otherLabel;        // Used for the "else" branch of if-then-else
+        NonAssertingLabel label;        // The "exit" label
+        NonAssertingLabel otherLabel;   // Used for the "else" branch of if-then-else
         uint32_t framePushed;           // From masm
         uint32_t stackSize;             // Value stack height
         bool deadOnArrival;             // deadCode_ was set on entry to the region
         bool deadThenBranch;            // deadCode_ was set on exit from "then"
     };
 
+    struct BaseCompilePolicy : OpIterPolicy
+    {
+        static const bool Output = true;
+
+        // The baseline compiler tracks values on a stack of its own -- it
+        // needs to scan that stack for spilling -- and thus has no need
+        // for the values maintained by the iterator.
+
+        // The baseline compiler uses the iterator's control stack, attaching
+        // its own control information.
+        typedef Control ControlItem;
+    };
+
+    typedef OpIter<BaseCompilePolicy> BaseOpIter;
+
     // Volatile registers except ReturnReg.
 
     static LiveRegisterSet VolatileReturnGPR;
 
     // The baseline compiler will use OOL code more sparingly than
     // Baldr since our code is not high performance and frills like
     // code density and branch prediction friendliness will be less
     // important.
@@ -531,18 +508,16 @@ class BaseCompiler
     MacroAssembler&             masm;            // No '_' suffix - too tedious...
 
     AllocatableGeneralRegisterSet availGPR_;
     AllocatableFloatRegisterSet availFPU_;
 #ifdef DEBUG
     bool                        scratchRegisterTaken_;
 #endif
 
-    TempObjectPool<PooledLabel> labelPool_;
-
     Vector<Local, 8, SystemAllocPolicy> localInfo_;
     Vector<OutOfLineCode*, 8, SystemAllocPolicy> outOfLine_;
 
     // Index into localInfo_ of the special local used for saving the TLS
     // pointer. This follows the function's real arguments and locals.
     uint32_t                    tlsSlot_;
 
     // On specific platforms we sometimes need to use specific registers.
@@ -570,17 +545,17 @@ class BaseCompiler
     // JoinRegI32 and joinRegI64 must overlap: emitBrIf and
     // emitBrTable assume that.
 
     RegI32 joinRegI32;
     RegI64 joinRegI64;
     RegF32 joinRegF32;
     RegF64 joinRegF64;
 
-    // More members: see the stk_ and ctl_ vectors, defined below.
+    // There are more members scattered throughout.
 
   public:
     BaseCompiler(const ModuleEnvironment& env,
                  Decoder& decoder,
                  const FuncBytes& func,
                  const ValTypeVector& locals,
                  bool debugEnabled,
                  TempAllocator* alloc,
@@ -2051,58 +2026,41 @@ class BaseCompiler
     Stk& peek(uint32_t relativeDepth) {
         return stk_[stk_.length()-1-relativeDepth];
     }
 
     ////////////////////////////////////////////////////////////
     //
     // Control stack
 
-    Vector<Control, 8, SystemAllocPolicy> ctl_;
-
-    MOZ_MUST_USE bool pushControl(UniquePooledLabel* label, UniquePooledLabel* otherLabel = nullptr)
+    void initControl(Control& item)
     {
-        uint32_t framePushed = masm.framePushed();
-        uint32_t stackSize = stk_.length();
-
-        if (!ctl_.emplaceBack(Control(framePushed, stackSize)))
-            return false;
-        ctl_.back().label = label->release();
-        if (otherLabel)
-            ctl_.back().otherLabel = otherLabel->release();
-        ctl_.back().deadOnArrival = deadCode_;
-        return true;
-    }
-
-    void popControl() {
-        Control last = ctl_.popCopy();
-        if (last.label)
-            freeLabel(last.label);
-        if (last.otherLabel)
-            freeLabel(last.otherLabel);
+        // Make sure the constructor was run properly
+        MOZ_ASSERT(item.framePushed == UINT32_MAX && item.stackSize == UINT32_MAX);
+
+        item.framePushed = masm.framePushed();
+        item.stackSize = stk_.length();
+        item.deadOnArrival = deadCode_;
+    }
+
+    Control& controlItem() {
+        return iter_.controlItem();
     }
 
     Control& controlItem(uint32_t relativeDepth) {
-        return ctl_[ctl_.length() - 1 - relativeDepth];
-    }
-
-    MOZ_MUST_USE PooledLabel* newLabel() {
-        // TODO / INVESTIGATE (Bug 1316819): allocate() is fallible, but we can
-        // probably rely on an infallible allocator here.  That would simplify
-        // code later.
-        PooledLabel* candidate = labelPool_.allocate();
-        if (!candidate)
-            return nullptr;
-        return new (candidate) PooledLabel(this);
-    }
-
-    void freeLabel(PooledLabel* label) {
-        label->~PooledLabel();
-        labelPool_.free(label);
-    }
+        return iter_.controlItem(relativeDepth);
+    }
+
+    Control& controlOutermost() {
+        return iter_.controlOutermost();
+    }
+
+    ////////////////////////////////////////////////////////////
+    //
+    // Labels
 
     void insertBreakablePoint(CallSiteDesc::Kind kind) {
         const uint32_t offset = iter_.currentOffset();
         masm.nopPatchableToCall(CallSiteDesc(offset, kind));
     }
 
     //////////////////////////////////////////////////////////////////////
     //
@@ -2585,17 +2543,17 @@ class BaseCompiler
         masm.flush();
 
         masm.bind(theTable);
 
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
         for (uint32_t i = 0; i < labels.length(); i++) {
             CodeLabel cl;
             masm.writeCodePointer(cl.patchAt());
-            cl.target()->bind(labels[i]->offset());
+            cl.target()->bind(labels[i].offset());
             masm.addCodeLabel(cl);
         }
 #else
         MOZ_CRASH("BaseCompiler platform hook: jumpTable");
 #endif
     }
 
     void tableSwitch(Label* theTable, RegI32 switchValue, Label* dispatchCode) {
@@ -2691,17 +2649,17 @@ class BaseCompiler
         if (call.usesSystemAbi && !call.hardFP)
             masm.ma_vxfer(r0, r1, rv);
 #endif
         return rv;
     }
 
     void returnCleanup(bool popStack) {
         if (popStack)
-            popStackBeforeBranch(ctl_[0].framePushed);
+            popStackBeforeBranch(controlOutermost().framePushed);
         masm.jump(&returnLabel_);
     }
 
     void pop2xI32ForIntMulDiv(RegI32* r0, RegI32* r1) {
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         // srcDest must be eax, and edx will be clobbered.
         need2xI32(specific_eax, specific_edx);
         *r1 = popI32();
@@ -5454,95 +5412,84 @@ BaseCompiler::emitBranchPerform(BranchSt
 //  - The exit value is always in a designated join register (type dependent).
 
 bool
 BaseCompiler::emitBlock()
 {
     if (!iter_.readBlock())
         return false;
 
-    UniquePooledLabel blockEnd(newLabel());
-    if (!blockEnd)
-        return false;
-
     if (!deadCode_)
         sync();                    // Simplifies branching out from block
 
-    return pushControl(&blockEnd);
+    initControl(controlItem());
+
+    return true;
 }
 
 void
 BaseCompiler::endBlock(ExprType type)
 {
-    Control& block = controlItem(0);
+    Control& block = controlItem();
 
     // Save the value.
     AnyReg r;
     if (!deadCode_)
         r = popJoinRegUnlessVoid(type);
 
     // Leave the block.
     popStackOnBlockExit(block.framePushed);
     popValueStackTo(block.stackSize);
 
     // Bind after cleanup: branches out will have popped the stack.
-    if (block.label->used()) {
-        masm.bind(block.label);
+    if (block.label.used()) {
+        masm.bind(&block.label);
         // No value was provided by the fallthrough but the branch out will
         // have stored one in joinReg, so capture that.
         if (deadCode_)
             r = captureJoinRegUnlessVoid(type);
         deadCode_ = false;
     }
 
-    popControl();
-
     // Retain the value stored in joinReg by all paths, if there are any.
     if (!deadCode_)
         pushJoinRegUnlessVoid(r);
 }
 
 bool
 BaseCompiler::emitLoop()
 {
     if (!iter_.readLoop())
         return false;
 
-    UniquePooledLabel blockCont(newLabel());
-    if (!blockCont)
-        return false;
-
     if (!deadCode_)
         sync();                    // Simplifies branching out from block
 
-    if (!pushControl(&blockCont))
-        return false;
+    initControl(controlItem());
 
     if (!deadCode_) {
-        masm.bind(controlItem(0).label);
+        masm.bind(&controlItem(0).label);
         addInterruptCheck();
     }
 
     return true;
 }
 
 void
 BaseCompiler::endLoop(ExprType type)
 {
-    Control& block = controlItem(0);
+    Control& block = controlItem();
 
     AnyReg r;
     if (!deadCode_)
         r = popJoinRegUnlessVoid(type);
 
     popStackOnBlockExit(block.framePushed);
     popValueStackTo(block.stackSize);
 
-    popControl();
-
     // Retain the value stored in joinReg by all paths.
     if (!deadCode_)
         pushJoinRegUnlessVoid(r);
 }
 
 // The bodies of the "then" and "else" arms can be arbitrary sequences
 // of expressions, they push control and increment the nesting and can
 // even be targeted by jumps.  A branch to the "if" block branches to
@@ -5559,65 +5506,55 @@ BaseCompiler::endLoop(ExprType type)
 
 bool
 BaseCompiler::emitIf()
 {
     Nothing unused_cond;
     if (!iter_.readIf(&unused_cond))
         return false;
 
-    UniquePooledLabel endLabel(newLabel());
-    if (!endLabel)
-        return false;
-
-    UniquePooledLabel elseLabel(newLabel());
-    if (!elseLabel)
-        return false;
-
-    BranchState b(elseLabel.get(), BranchState::NoPop, InvertBranch(true));
+    BranchState b(&controlItem().otherLabel, BranchState::NoPop, InvertBranch(true));
     if (!deadCode_) {
         emitBranchSetup(&b);
         sync();
     } else {
         resetLatentOp();
     }
 
-    if (!pushControl(&endLabel, &elseLabel))
-        return false;
+    initControl(controlItem());
 
     if (!deadCode_)
         emitBranchPerform(&b);
 
     return true;
 }
 
 void
 BaseCompiler::endIfThen()
 {
-    Control& ifThen = controlItem(0);
+    Control& ifThen = controlItem();
 
     popStackOnBlockExit(ifThen.framePushed);
     popValueStackTo(ifThen.stackSize);
 
-    if (ifThen.otherLabel->used())
-        masm.bind(ifThen.otherLabel);
-
-    if (ifThen.label->used())
-        masm.bind(ifThen.label);
+    if (ifThen.otherLabel.used())
+        masm.bind(&ifThen.otherLabel);
+
+    if (ifThen.label.used())
+        masm.bind(&ifThen.label);
 
     deadCode_ = ifThen.deadOnArrival;
-
-    popControl();
 }
 
 bool
 BaseCompiler::emitElse()
 {
     ExprType thenType;
     Nothing unused_thenValue;
+
     if (!iter_.readElse(&thenType, &unused_thenValue))
         return false;
 
     Control& ifThenElse = controlItem(0);
 
     // See comment in endIfThenElse, below.
 
     // Exit the "then" branch.
@@ -5627,87 +5564,88 @@ BaseCompiler::emitElse()
     AnyReg r;
     if (!deadCode_)
         r = popJoinRegUnlessVoid(thenType);
 
     popStackOnBlockExit(ifThenElse.framePushed);
     popValueStackTo(ifThenElse.stackSize);
 
     if (!deadCode_)
-        masm.jump(ifThenElse.label);
-
-    if (ifThenElse.otherLabel->used())
-        masm.bind(ifThenElse.otherLabel);
+        masm.jump(&ifThenElse.label);
+
+    if (ifThenElse.otherLabel.used())
+        masm.bind(&ifThenElse.otherLabel);
 
     // Reset to the "else" branch.
 
     if (!deadCode_)
         freeJoinRegUnlessVoid(r);
 
     deadCode_ = ifThenElse.deadOnArrival;
 
     return true;
 }
 
 void
 BaseCompiler::endIfThenElse(ExprType type)
 {
-    Control& ifThenElse = controlItem(0);
+    Control& ifThenElse = controlItem();
 
     // The expression type is not a reliable guide to what we'll find
     // on the stack, we could have (if E (i32.const 1) (unreachable))
     // in which case the "else" arm is AnyType but the type of the
     // full expression is I32.  So restore whatever's there, not what
     // we want to find there.  The "then" arm has the same constraint.
 
     AnyReg r;
 
     if (!deadCode_)
         r = popJoinRegUnlessVoid(type);
 
     popStackOnBlockExit(ifThenElse.framePushed);
     popValueStackTo(ifThenElse.stackSize);
 
-    if (ifThenElse.label->used())
-        masm.bind(ifThenElse.label);
+    if (ifThenElse.label.used())
+        masm.bind(&ifThenElse.label);
 
     bool joinLive = !ifThenElse.deadOnArrival &&
-                    (!ifThenElse.deadThenBranch || !deadCode_ || ifThenElse.label->bound());
+                    (!ifThenElse.deadThenBranch || !deadCode_ || ifThenElse.label.bound());
 
     if (joinLive) {
         // No value was provided by the "then" path but capture the one
         // provided by the "else" path.
         if (deadCode_)
             r = captureJoinRegUnlessVoid(type);
         deadCode_ = false;
     }
 
-    popControl();
-
     if (!deadCode_)
         pushJoinRegUnlessVoid(r);
 }
 
 bool
 BaseCompiler::emitEnd()
 {
     LabelKind kind;
     ExprType type;
     Nothing unused_value;
+
     if (!iter_.readEnd(&kind, &type, &unused_value))
         return false;
 
     switch (kind) {
       case LabelKind::Block: endBlock(type); break;
       case LabelKind::Loop:  endLoop(type); break;
       case LabelKind::UnreachableThen:
       case LabelKind::Then:  endIfThen(); break;
       case LabelKind::Else:  endIfThenElse(type); break;
     }
 
+    iter_.popEnd();
+
     return true;
 }
 
 bool
 BaseCompiler::emitBr()
 {
     uint32_t relativeDepth;
     ExprType type;
@@ -5721,17 +5659,17 @@ BaseCompiler::emitBr()
     Control& target = controlItem(relativeDepth);
 
     // Save any value in the designated join register, where the
     // normal block exit code will also leave it.
 
     AnyReg r = popJoinRegUnlessVoid(type);
 
     popStackBeforeBranch(target.framePushed);
-    masm.jump(target.label);
+    masm.jump(&target.label);
 
     // The register holding the join value is free for the remainder
     // of this block.
 
     freeJoinRegUnlessVoid(r);
 
     deadCode_ = true;
 
@@ -5749,17 +5687,17 @@ BaseCompiler::emitBrIf()
 
     if (deadCode_) {
         resetLatentOp();
         return true;
     }
 
     Control& target = controlItem(relativeDepth);
 
-    BranchState b(target.label, target.framePushed, InvertBranch(false), type);
+    BranchState b(&target.label, target.framePushed, InvertBranch(false), type);
     emitBranchSetup(&b);
     emitBranchPerform(&b);
 
     return true;
 }
 
 bool
 BaseCompiler::emitBrTable()
@@ -5803,36 +5741,32 @@ BaseCompiler::emitBrTable()
     AnyReg r = popJoinRegUnlessVoid(type);
 
     Label dispatchCode;
     masm.branch32(Assembler::Below, rc, Imm32(tableLength), &dispatchCode);
 
     // This is the out-of-range stub.  rc is dead here but we don't need it.
 
     popStackBeforeBranch(controlItem(defaultDepth).framePushed);
-    masm.jump(controlItem(defaultDepth).label);
+    masm.jump(&controlItem(defaultDepth).label);
 
     // Emit stubs.  rc is dead in all of these but we don't need it.
     //
     // The labels in the vector are in the TempAllocator and will
     // be freed by and by.
     //
     // TODO / OPTIMIZE (Bug 1316804): Branch directly to the case code if we
     // can, don't emit an intermediate stub.
 
     for (uint32_t i = 0; i < tableLength; i++) {
-        PooledLabel* stubLabel = newLabel();
-        if (!stubLabel)
-            return false;
-
-        stubs.infallibleAppend(stubLabel);
-        masm.bind(stubLabel);
+        stubs.infallibleEmplaceBack(NonAssertingLabel());
+        masm.bind(&stubs.back());
         uint32_t k = depths[i];
         popStackBeforeBranch(controlItem(k).framePushed);
-        masm.jump(controlItem(k).label);
+        masm.jump(&controlItem(k).label);
     }
 
     // Emit table.
 
     Label theTable;
     jumpTable(stubs, &theTable);
 
     // Emit indirect jump.  rc is live here.
@@ -5841,19 +5775,16 @@ BaseCompiler::emitBrTable()
 
     deadCode_ = true;
 
     // Clean up.
 
     freeI32(rc);
     freeJoinRegUnlessVoid(r);
 
-    for (uint32_t i = 0; i < tableLength; i++)
-        freeLabel(stubs[i]);
-
     return true;
 }
 
 bool
 BaseCompiler::emitDrop()
 {
     if (!iter_.readDrop())
         return false;
@@ -7659,38 +7590,24 @@ BaseCompiler::emitBody()
 
 done:
     return false;
 }
 
 bool
 BaseCompiler::emitFunction()
 {
-    // emitBody() will ensure that there is enough memory reserved in the
-    // vector for infallible allocation to succeed within the compiler, but we
-    // need a little headroom for the initial pushControl(), which pushes a
-    // void value onto the value stack.
-
-    if (!stk_.reserve(8))
-        return false;
-
     const Sig& sig = func_.sig();
 
     if (!iter_.readFunctionStart(sig.ret()))
         return false;
 
     beginFunction();
 
-    UniquePooledLabel functionEnd(newLabel());
-    if (!functionEnd)
-        return false;
-
-    // For the function's block; it will be popped by endBlock().
-    if (!pushControl(&functionEnd))
-        return false;
+    initControl(controlItem());
 
     if (!emitBody())
         return false;
 
     if (!deadCode_)
         doReturn(sig.ret(), PopStack(false));
 
     if (!iter_.readFunctionEnd())
@@ -7769,18 +7686,16 @@ BaseCompiler::BaseCompiler(const ModuleE
     availGPR_.take(HeapLenReg);
     availGPR_.take(GlobalReg);
 #elif defined(JS_CODEGEN_X86)
     availGPR_.take(ScratchRegX86);
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     availGPR_.take(HeapReg);
     availGPR_.take(GlobalReg);
 #endif
-
-    labelPool_.setAllocator(alloc_);
 }
 
 bool
 BaseCompiler::init()
 {
     if (!SigDD_.append(ValType::F64) || !SigDD_.append(ValType::F64))
         return false;
     if (!SigD_.append(ValType::F64))
--- a/js/src/wasm/WasmBinaryIterator.h
+++ b/js/src/wasm/WasmBinaryIterator.h
@@ -146,17 +146,16 @@ class ControlStackEntry
     ControlItem& controlItem() { return controlItem_; }
 
     void setReachable() { reachable_ = true; }
 
     void switchToElse(bool reachable) {
         MOZ_ASSERT(kind_ == LabelKind::Then || kind_ == LabelKind::UnreachableThen);
         reachable_ = reachable;
         kind_ = LabelKind::Else;
-        controlItem_ = ControlItem();
     }
 };
 
 // Specialization for when there is no additional data needed.
 template <>
 class ControlStackEntry<Nothing>
 {
     LabelKind kind_;
@@ -378,18 +377,18 @@ class MOZ_STACK_CLASS OpIter : private P
     MOZ_MUST_USE bool readLinearMemoryAddress(uint32_t byteSize, LinearMemoryAddress<Value>* addr);
     MOZ_MUST_USE bool readBlockType(ExprType* expr);
 
     MOZ_MUST_USE bool typeMismatch(ExprType actual, ExprType expected) MOZ_COLD;
     MOZ_MUST_USE bool checkType(ValType actual, ValType expected);
     MOZ_MUST_USE bool checkType(ExprType actual, ExprType expected);
 
     MOZ_MUST_USE bool pushControl(LabelKind kind, ExprType type, bool reachable);
-    MOZ_MUST_USE bool mergeControl(LabelKind* kind, ExprType* type, Value* value);
-    MOZ_MUST_USE bool popControl(LabelKind* kind, ExprType* type, Value* value);
+    MOZ_MUST_USE bool checkControlAtEndOfBlock(LabelKind* kind, ExprType* type, Value* value);
+    MOZ_MUST_USE bool finishControl(LabelKind* kind, ExprType* type, Value* value);
 
     MOZ_MUST_USE bool push(ValType t) {
         if (MOZ_UNLIKELY(!reachable_))
             return true;
         return valueStack_.emplaceBack(t);
     }
     MOZ_MUST_USE bool push(TypeAndValue<Value> tv) {
         if (MOZ_UNLIKELY(!reachable_))
@@ -489,19 +488,26 @@ class MOZ_STACK_CLASS OpIter : private P
     bool getControl(uint32_t relativeDepth, ControlStackEntry<ControlItem>** controlEntry) {
         if (Validate && relativeDepth >= controlStack_.length())
             return fail("branch depth exceeds current nesting level");
 
         *controlEntry = &controlStack_[controlStack_.length() - 1 - relativeDepth];
         return true;
     }
 
-    void enterUnreachableCode() {
+    MOZ_MUST_USE bool enterUnreachableCode() {
+        if (Validate) {
+            uint16_t op = peekOp();
+            if (op != uint16_t(Op::End) && op != uint16_t(Op::Else))
+                return fail("non-fallthrough instruction must be followed by end or else");
+        }
+
         valueStack_.shrinkTo(controlStack_.back().valueStackStart());
         reachable_ = false;
+        return true;
     }
 
     bool checkBrValue(uint32_t relativeDepth, ExprType* type, Value* value);
     bool checkBrIfValues(uint32_t relativeDepth, Value* condition, ExprType* type, Value* value);
 
   public:
     explicit OpIter(Decoder& decoder, uint32_t offsetInModule = 0)
       : d_(decoder), offsetInModule_(offsetInModule), reachable_(true),
@@ -538,16 +544,17 @@ class MOZ_STACK_CLASS OpIter : private P
     MOZ_MUST_USE bool readFunctionStart(ExprType ret);
     MOZ_MUST_USE bool readFunctionEnd();
     MOZ_MUST_USE bool readReturn(Value* value);
     MOZ_MUST_USE bool readBlock();
     MOZ_MUST_USE bool readLoop();
     MOZ_MUST_USE bool readIf(Value* condition);
     MOZ_MUST_USE bool readElse(ExprType* thenType, Value* thenValue);
     MOZ_MUST_USE bool readEnd(LabelKind* kind, ExprType* type, Value* value);
+    void popEnd();
     MOZ_MUST_USE bool readBr(uint32_t* relativeDepth, ExprType* type, Value* value);
     MOZ_MUST_USE bool readBrIf(uint32_t* relativeDepth, ExprType* type,
                                Value* value, Value* condition);
     MOZ_MUST_USE bool readBrTable(uint32_t* tableLength, ExprType* type,
                                   Value* value, Value* index);
     MOZ_MUST_USE bool readBrTableEntry(ExprType* type, Value* value, uint32_t* depth);
     MOZ_MUST_USE bool readBrTableDefault(ExprType* type, Value* value, uint32_t* depth);
     MOZ_MUST_USE bool readUnreachable();
@@ -649,16 +656,26 @@ class MOZ_STACK_CLASS OpIter : private P
         return valueStack_.back().value();
     }
 
     // Return a reference to the top of the control stack.
     ControlItem& controlItem() {
         return controlStack_.back().controlItem();
     }
 
+    // Return a reference to an element in the control stack.
+    ControlItem& controlItem(uint32_t relativeDepth) {
+        return controlStack_[controlStack_.length() - 1 - relativeDepth].controlItem();
+    }
+
+    // Return a reference to the outermost element on the control stack.
+    ControlItem& controlOutermost() {
+        return controlStack_[0].controlItem();
+    }
+
     // Return the signature of the top of the control stack.
     ExprType controlType() {
         return controlStack_.back().type();
     }
 
     // Test whether the control-stack is empty, meaning we've consumed the final
     // end of the function body.
     bool controlStackEmpty() const {
@@ -738,17 +755,17 @@ template <typename Policy>
 inline bool
 OpIter<Policy>::pushControl(LabelKind kind, ExprType type, bool reachable)
 {
     return controlStack_.emplaceBack(kind, type, reachable, valueStack_.length());
 }
 
 template <typename Policy>
 inline bool
-OpIter<Policy>::mergeControl(LabelKind* kind, ExprType* type, Value* value)
+OpIter<Policy>::checkControlAtEndOfBlock(LabelKind* kind, ExprType* type, Value* value)
 {
     MOZ_ASSERT(!controlStack_.empty());
 
     ControlStackEntry<ControlItem>& controlItem = controlStack_.back();
     *kind = controlItem.kind();
 
     if (reachable_) {
         // Unlike branching, exiting a scope via fallthrough does not implicitly
@@ -786,35 +803,30 @@ OpIter<Policy>::mergeControl(LabelKind* 
             *value = Value();
     }
 
     return true;
 }
 
 template <typename Policy>
 inline bool
-OpIter<Policy>::popControl(LabelKind* kind, ExprType* type, Value* value)
+OpIter<Policy>::finishControl(LabelKind* kind, ExprType* type, Value* value)
 {
-    if (!mergeControl(kind, type, value))
+    if (!checkControlAtEndOfBlock(kind, type, value))
         return false;
 
     if (*kind == LabelKind::Then) {
         // A reachable If without an Else. Forbid a result value.
         if (reachable_) {
             if (Validate && !IsVoid(*type))
                 return fail("if without else with a result value");
         }
         reachable_ = true;
     }
 
-    controlStack_.popBack();
-
-    if (!reachable_ && !controlStack_.empty())
-        valueStack_.shrinkTo(controlStack_.back().valueStackStart());
-
     return true;
 }
 
 template <typename Policy>
 inline bool
 OpIter<Policy>::readBlockType(ExprType* type)
 {
     uint8_t unchecked;
@@ -923,18 +935,17 @@ OpIter<Policy>::readReturn(Value* value)
         controlItem.setReachable();
 
         if (!IsVoid(controlItem.type())) {
             if (!popWithType(NonVoidToValType(controlItem.type()), value))
                 return false;
         }
     }
 
-    enterUnreachableCode();
-    return true;
+    return enterUnreachableCode();
 }
 
 template <typename Policy>
 inline bool
 OpIter<Policy>::readBlock()
 {
     MOZ_ASSERT(Classify(op_) == OpKind::Block);
 
@@ -982,17 +993,17 @@ template <typename Policy>
 inline bool
 OpIter<Policy>::readElse(ExprType* thenType, Value* thenValue)
 {
     MOZ_ASSERT(Classify(op_) == OpKind::Else);
 
     // Finish up the then arm.
     ExprType type = ExprType::Limit;
     LabelKind kind;
-    if (!mergeControl(&kind, &type, thenValue))
+    if (!checkControlAtEndOfBlock(&kind, &type, thenValue))
         return false;
 
     if (Output)
         *thenType = type;
 
     // Pop the old then value from the stack.
     if (!IsVoid(type))
         valueStack_.popBack();
@@ -1013,28 +1024,40 @@ OpIter<Policy>::readElse(ExprType* thenT
 template <typename Policy>
 inline bool
 OpIter<Policy>::readEnd(LabelKind* kind, ExprType* type, Value* value)
 {
     MOZ_ASSERT(Classify(op_) == OpKind::End);
 
     LabelKind validateKind = static_cast<LabelKind>(-1);
     ExprType validateType = ExprType::Limit;
-    if (!popControl(&validateKind, &validateType, value))
+    if (!finishControl(&validateKind, &validateType, value))
         return false;
 
     if (Output) {
         *kind = validateKind;
         *type = validateType;
     }
 
     return true;
 }
 
 template <typename Policy>
+inline void
+OpIter<Policy>::popEnd()
+{
+    MOZ_ASSERT(Classify(op_) == OpKind::End);
+
+    controlStack_.popBack();
+
+    if (!reachable_ && !controlStack_.empty())
+        valueStack_.shrinkTo(controlStack_.back().valueStackStart());
+}
+
+template <typename Policy>
 inline bool
 OpIter<Policy>::checkBrValue(uint32_t relativeDepth, ExprType* type, Value* value)
 {
     if (MOZ_LIKELY(reachable_)) {
         ControlStackEntry<ControlItem>* controlItem = nullptr;
         if (!getControl(relativeDepth, &controlItem))
             return false;
 
@@ -1069,18 +1092,17 @@ OpIter<Policy>::readBr(uint32_t* relativ
         return fail("unable to read br depth");
 
     if (!checkBrValue(validateRelativeDepth, type, value))
         return false;
 
     if (Output)
         *relativeDepth = validateRelativeDepth;
 
-    enterUnreachableCode();
-    return true;
+    return enterUnreachableCode();
 }
 
 template <typename Policy>
 inline bool
 OpIter<Policy>::checkBrIfValues(uint32_t relativeDepth, Value* condition,
                                   ExprType* type, Value* value)
 {
     if (MOZ_LIKELY(reachable_)) {
@@ -1199,28 +1221,26 @@ template <typename Policy>
 inline bool
 OpIter<Policy>::readBrTableDefault(ExprType* type, Value* value, uint32_t* depth)
 {
     if (!readBrTableEntry(type, value, depth))
         return false;
 
     MOZ_ASSERT(!reachable_ || *type != ExprType::Limit);
 
-    enterUnreachableCode();
-    return true;
+    return enterUnreachableCode();
 }
 
 template <typename Policy>
 inline bool
 OpIter<Policy>::readUnreachable()
 {
     MOZ_ASSERT(Classify(op_) == OpKind::Unreachable);
 
-    enterUnreachableCode();
-    return true;
+    return enterUnreachableCode();
 }
 
 template <typename Policy>
 inline bool
 OpIter<Policy>::readDrop()
 {
     MOZ_ASSERT(Classify(op_) == OpKind::Drop);
 
--- a/js/src/wasm/WasmBinaryToAST.cpp
+++ b/js/src/wasm/WasmBinaryToAST.cpp
@@ -594,16 +594,18 @@ AstDecodeIf(AstDecodeContext& c)
 static bool
 AstDecodeEnd(AstDecodeContext& c)
 {
     LabelKind kind;
     ExprType type;
     if (!c.iter().readEnd(&kind, &type, nullptr))
         return false;
 
+    c.iter().popEnd();
+
     if (!c.push(AstDecodeStackItem(AstDecodeTerminationKind::End, type)))
         return false;
 
     return true;
 }
 
 static bool
 AstDecodeElse(AstDecodeContext& c)
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -1657,43 +1657,43 @@ EmitIf(FunctionCompiler& f)
 
     f.iter().controlItem() = elseBlock;
     return true;
 }
 
 static bool
 EmitElse(FunctionCompiler& f)
 {
-    MBasicBlock* block = f.iter().controlItem();
-
     ExprType thenType;
     MDefinition* thenValue;
     if (!f.iter().readElse(&thenType, &thenValue))
         return false;
 
     if (!IsVoid(thenType))
         f.pushDef(thenValue);
 
-    if (!f.switchToElse(block, &f.iter().controlItem()))
+    if (!f.switchToElse(f.iter().controlItem(), &f.iter().controlItem()))
         return false;
 
     return true;
 }
 
 static bool
 EmitEnd(FunctionCompiler& f)
 {
-    MBasicBlock* block = f.iter().controlItem();
-
     LabelKind kind;
     ExprType type;
     MDefinition* value;
     if (!f.iter().readEnd(&kind, &type, &value))
         return false;
 
+    MBasicBlock* block = f.iter().controlItem();
+
+    f.iter().popEnd();
+
     if (!IsVoid(type))
         f.pushDef(value);
 
     MDefinition* def = nullptr;
     switch (kind) {
       case LabelKind::Block:
         if (!f.finishBlock(&def))
             return false;
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -419,16 +419,17 @@ DecodeFunctionBodyExprs(FunctionDecoder&
         uint16_t op;
         if (!f.iter().readOp(&op))
             return false;
 
         switch (op) {
           case uint16_t(Op::End):
             if (!f.iter().readEnd(nullptr, nullptr, nullptr))
                 return false;
+            f.iter().popEnd();
             if (f.iter().controlStackEmpty())
                 return true;
             break;
           case uint16_t(Op::Nop):
             CHECK(f.iter().readNop());
           case uint16_t(Op::Drop):
             CHECK(f.iter().readDrop());
           case uint16_t(Op::Call):
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3012,21 +3012,27 @@ nsXPCComponents_Utils::SetGCZeal(int32_t
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx)
 {
     PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS);
     NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG);
     JSObject* wrapper = &obj.toObject();
     NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG);
-    JSObject* sb = UncheckedUnwrap(wrapper);
+    RootedObject sb(cx, UncheckedUnwrap(wrapper));
     NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG);
     NukeCrossCompartmentWrappers(cx, AllCompartments(),
                                  SingleCompartment(GetObjectCompartment(sb)),
                                  NukeWindowReferences);
+
+    // Now mark the compartment as nuked and non-scriptable.
+    auto compartmentPrivate = xpc::CompartmentPrivate::Get(sb);
+    compartmentPrivate->wasNuked = true;
+    compartmentPrivate->scriptability.Block();
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg,
                                             JSContext* cx)
 {
     NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -519,17 +519,23 @@ XPCConvert::JSData2Native(void* d, Handl
         nsAString* ws = *((nsAString**)d);
 
         if (!str) {
             ws->AssignLiteral(u"undefined");
         } else if (XPCStringConvert::IsDOMString(str)) {
             // The characters represent an existing nsStringBuffer that
             // was shared by XPCStringConvert::ReadableToJSVal.
             const char16_t* chars = JS_GetTwoByteExternalStringChars(str);
-            nsStringBuffer::FromData((void*)chars)->ToString(length, *ws);
+            if (chars[length] == '\0') {
+                // Safe to share the buffer.
+                nsStringBuffer::FromData((void*)chars)->ToString(length, *ws);
+            } else {
+                // We have to copy to ensure null-termination.
+                ws->Assign(chars, length);
+            }
         } else if (XPCStringConvert::IsLiteral(str)) {
             // The characters represent a literal char16_t string constant
             // compiled into libxul, such as the string "undefined" above.
             const char16_t* chars = JS_GetTwoByteExternalStringChars(str);
             ws->AssignLiteral(chars, length);
         } else {
             if (!AssignJSString(cx, *ws, str))
                 return false;
--- a/js/xpconnect/src/XPCForwards.h
+++ b/js/xpconnect/src/XPCForwards.h
@@ -23,17 +23,16 @@ class nsXPCWrappedJSClass;
 
 class XPCNativeMember;
 class XPCNativeInterface;
 class XPCNativeSet;
 
 class XPCWrappedNative;
 class XPCWrappedNativeProto;
 class XPCWrappedNativeTearOff;
-class XPCNativeScriptableCreateInfo;
 
 class XPCTraceableVariant;
 class XPCJSObjectHolder;
 
 class JSObject2WrappedJSMap;
 class Native2WrappedNativeMap;
 class IID2WrappedJSClassMap;
 class IID2NativeInterfaceMap;
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -194,16 +194,17 @@ CompartmentPrivate::CompartmentPrivate(J
     , allowWaivers(true)
     , writeToGlobalPrototype(false)
     , skipWriteToGlobalPrototype(false)
     , isWebExtensionContentScript(false)
     , waiveInterposition(false)
     , allowCPOWs(false)
     , universalXPConnectEnabled(false)
     , forcePermissiveCOWs(false)
+    , wasNuked(false)
     , scriptability(c)
     , scope(nullptr)
     , mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH))
 {
     MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
     mozilla::PodArrayZero(wrapperDenialWarnings);
 }
 
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -159,30 +159,26 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
 
     // The object should specify that it's meant to be global.
     MOZ_ASSERT(nativeHelper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
 
     // We shouldn't be reusing globals.
     MOZ_ASSERT(!nativeHelper.GetWrapperCache() ||
                !nativeHelper.GetWrapperCache()->GetWrapperPreserveColor());
 
-    // Put together the ScriptableCreateInfo...
-    XPCNativeScriptableCreateInfo sciProto;
-    XPCNativeScriptableCreateInfo sciMaybe;
-    const XPCNativeScriptableCreateInfo& sciWrapper =
-        GatherScriptableCreateInfo(identity, nativeHelper.GetClassInfo(),
-                                   sciProto, sciMaybe);
-
-    // ...and then get the nsIXPCScriptable. This will tell us the JSClass of
-    // the object we're going to create.
-    nsCOMPtr<nsIXPCScriptable> scr = sciWrapper.GetCallback();
-    MOZ_ASSERT(scr);
+    // Get the nsIXPCScriptable. This will tell us the JSClass of the object
+    // we're going to create.
+    nsCOMPtr<nsIXPCScriptable> scrProto;
+    nsCOMPtr<nsIXPCScriptable> scrWrapper;
+    GatherScriptable(identity, nativeHelper.GetClassInfo(),
+                     getter_AddRefs(scrProto), getter_AddRefs(scrWrapper));
+    MOZ_ASSERT(scrWrapper);
 
     // Finally, we get to the JSClass.
-    const JSClass* clasp = scr->GetJSClass();
+    const JSClass* clasp = scrWrapper->GetJSClass();
     MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
 
     // Create the global.
     aOptions.creationOptions().setTrace(XPCWrappedNative::Trace);
     if (xpc::SharedMemoryEnabled())
         aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
     RootedObject global(cx, xpc::CreateGlobalObject(cx, clasp, principal, aOptions));
     if (!global)
@@ -195,17 +191,18 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
 
     // If requested, initialize the standard classes on the global.
     if (initStandardClasses && ! JS_InitStandardClasses(cx, global))
         return NS_ERROR_FAILURE;
 
     // Make a proto.
     XPCWrappedNativeProto* proto =
         XPCWrappedNativeProto::GetNewOrUsed(scope,
-                                            nativeHelper.GetClassInfo(), &sciProto,
+                                            nativeHelper.GetClassInfo(),
+                                            scrProto,
                                             /* callPostCreatePrototype = */ false);
     if (!proto)
         return NS_ERROR_FAILURE;
 
     // Set up the prototype on the global.
     MOZ_ASSERT(proto->GetJSProtoObject());
     RootedObject protoObj(cx, proto->GetJSProtoObject());
     bool success = JS_SplicePrototype(cx, global, protoObj);
@@ -217,17 +214,17 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
     RefPtr<XPCWrappedNative> wrapper =
         new XPCWrappedNative(nativeHelper.forgetCanonical(), proto);
 
     //
     // We don't call ::Init() on this wrapper, because our setup requirements
     // are different for globals. We do our setup inline here, instead.
     //
 
-    wrapper->mScriptable = scr;
+    wrapper->mScriptable = scrWrapper;
 
     // Set the JS object to the global we already created.
     wrapper->mFlatJSObject = global;
     wrapper->mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
 
     // Set the private to the XPCWrappedNative.
     JS_SetPrivate(global, wrapper);
 
@@ -325,35 +322,34 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
     uint32_t classInfoFlags;
     bool isClassInfoSingleton = helper.GetClassInfo() == helper.Object() &&
                                 NS_SUCCEEDED(helper.GetClassInfo()
                                                    ->GetFlags(&classInfoFlags)) &&
                                 (classInfoFlags & nsIClassInfo::SINGLETON_CLASSINFO);
 
     nsIClassInfo* info = helper.GetClassInfo();
 
-    XPCNativeScriptableCreateInfo sciProto;
-    XPCNativeScriptableCreateInfo sci;
+    nsCOMPtr<nsIXPCScriptable> scrProto;
+    nsCOMPtr<nsIXPCScriptable> scrWrapper;
 
     // Gather scriptable create info if we are wrapping something
     // other than an nsIClassInfo object. We need to not do this for
     // nsIClassInfo objects because often nsIClassInfo implementations
     // are also nsIXPCScriptable helper implementations, but the helper
     // code is obviously intended for the implementation of the class
     // described by the nsIClassInfo, not for the class info object
     // itself.
-    const XPCNativeScriptableCreateInfo& sciWrapper =
-        isClassInfoSingleton ? sci :
-        GatherScriptableCreateInfo(identity, info, sciProto, sci);
+    if (!isClassInfoSingleton)
+        GatherScriptable(identity, info, getter_AddRefs(scrProto),
+                         getter_AddRefs(scrWrapper));
 
     RootedObject parent(cx, Scope->GetGlobalJSObject());
 
     mozilla::Maybe<JSAutoCompartment> ac;
 
-    nsCOMPtr<nsIXPCScriptable> scrWrapper = sciWrapper.GetCallback();
     if (scrWrapper && scrWrapper->WantPreCreate()) {
         RootedObject plannedParent(cx, parent);
         nsresult rv =
             scrWrapper->PreCreate(identity, cx, parent, parent.address());
         if (NS_FAILED(rv))
             return rv;
         rv = NS_OK;
 
@@ -400,17 +396,17 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
 
     // If there is ClassInfo (and we are not building a wrapper for the
     // nsIClassInfo interface) then we use a wrapper that needs a prototype.
 
     // Note that the security check happens inside FindTearOff - after the
     // wrapper is actually created, but before JS code can see it.
 
     if (info && !isClassInfoSingleton) {
-        proto = XPCWrappedNativeProto::GetNewOrUsed(Scope, info, &sciProto);
+        proto = XPCWrappedNativeProto::GetNewOrUsed(Scope, info, scrProto);
         if (!proto)
             return NS_ERROR_FAILURE;
 
         wrapper = new XPCWrappedNative(helper.forgetCanonical(), proto);
     } else {
         RefPtr<XPCNativeInterface> iface = Interface;
         if (!iface)
             iface = XPCNativeInterface::GetISupports();
@@ -430,17 +426,17 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
                "Xray wrapper being used to parent XPCWrappedNative?");
 
     // We use an AutoMarkingPtr here because it is possible for JS gc to happen
     // after we have Init'd the wrapper but *before* we add it to the hashtable.
     // This would cause the mSet to get collected and we'd later crash. I've
     // *seen* this happen.
     AutoMarkingWrappedNativePtr wrapperMarker(cx, wrapper);
 
-    if (!wrapper->Init(&sciWrapper))
+    if (!wrapper->Init(scrWrapper))
         return NS_ERROR_FAILURE;
 
     if (!wrapper->FindTearOff(Interface, false, &rv)) {
         MOZ_ASSERT(NS_FAILED(rv), "returning NS_OK on failure");
         return rv;
     }
 
     return FinishCreate(Scope, Interface, cache, wrapper, resultWrapper);
@@ -603,117 +599,116 @@ XPCWrappedNative::SetProto(XPCWrappedNat
 
     // Write barrier for incremental GC.
     JSContext* cx = GetContext()->Context();
     GetProto()->WriteBarrierPre(cx);
 
     mMaybeProto = p;
 }
 
-// This is factored out so that it can be called publicly
+// This is factored out so that it can be called publicly.
 // static
-void
-XPCWrappedNative::GatherProtoScriptableCreateInfo(nsIClassInfo* classInfo,
-                                                  XPCNativeScriptableCreateInfo& sciProto)
+nsIXPCScriptable*
+XPCWrappedNative::GatherProtoScriptable(nsIClassInfo* classInfo)
 {
     MOZ_ASSERT(classInfo, "bad param");
-    MOZ_ASSERT(!sciProto.GetCallback(), "bad param");
 
     nsXPCClassInfo* classInfoHelper = nullptr;
     CallQueryInterface(classInfo, &classInfoHelper);
     if (classInfoHelper) {
         nsCOMPtr<nsIXPCScriptable> helper =
           dont_AddRef(static_cast<nsIXPCScriptable*>(classInfoHelper));
-        sciProto.SetCallback(helper.forget());
-
-        return;
+        return helper;
     }
 
     nsCOMPtr<nsIXPCScriptable> helper;
     nsresult rv = classInfo->GetScriptableHelper(getter_AddRefs(helper));
     if (NS_SUCCEEDED(rv) && helper) {
-        sciProto.SetCallback(helper.forget());
+        return helper;
     }
+
+    return nullptr;
 }
 
 // static
-const XPCNativeScriptableCreateInfo&
-XPCWrappedNative::GatherScriptableCreateInfo(nsISupports* obj,
-                                             nsIClassInfo* classInfo,
-                                             XPCNativeScriptableCreateInfo& sciProto,
-                                             XPCNativeScriptableCreateInfo& sciWrapper)
+void
+XPCWrappedNative::GatherScriptable(nsISupports* aObj,
+                                   nsIClassInfo* aClassInfo,
+                                   nsIXPCScriptable** aScrProto,
+                                   nsIXPCScriptable** aScrWrapper)
 {
-    MOZ_ASSERT(!sciWrapper.GetCallback(), "bad param");
+    MOZ_ASSERT(!*aScrProto, "bad param");
+    MOZ_ASSERT(!*aScrWrapper, "bad param");
+
+    nsCOMPtr<nsIXPCScriptable> scrProto;
+    nsCOMPtr<nsIXPCScriptable> scrWrapper;
 
     // Get the class scriptable helper (if present)
-    if (classInfo) {
-        GatherProtoScriptableCreateInfo(classInfo, sciProto);
+    if (aClassInfo) {
+        scrProto = GatherProtoScriptable(aClassInfo);
 
-        nsCOMPtr<nsIXPCScriptable> scrProto = sciProto.GetCallback();
-        if (scrProto && scrProto->DontAskInstanceForScriptable())
-            return sciProto;
+        if (scrProto && scrProto->DontAskInstanceForScriptable()) {
+            scrWrapper = scrProto;
+            scrProto.forget(aScrProto);
+            scrWrapper.forget(aScrWrapper);
+            return;
+        }
     }
 
     // Do the same for the wrapper specific scriptable
-    nsCOMPtr<nsIXPCScriptable> scrWrapper(do_QueryInterface(obj));
+    scrWrapper = do_QueryInterface(aObj);
     if (scrWrapper) {
         // A whole series of assertions to catch bad uses of scriptable flags on
-        // the siWrapper...
+        // the scrWrapper...
 
         // Can't set WANT_PRECREATE on an instance scriptable without also
         // setting it on the class scriptable.
         MOZ_ASSERT_IF(scrWrapper->WantPreCreate(),
-                      sciProto.GetCallback() &&
-                      sciProto.GetCallback()->WantPreCreate());
+                      scrProto && scrProto->WantPreCreate());
 
         // Can't set DONT_ENUM_QUERY_INTERFACE on an instance scriptable
         // without also setting it on the class scriptable (if present).
-        MOZ_ASSERT_IF(scrWrapper->DontEnumQueryInterface() &&
-                      sciProto.GetCallback(),
-                      sciProto.GetCallback()->DontEnumQueryInterface());
+        MOZ_ASSERT_IF(scrWrapper->DontEnumQueryInterface() && scrProto,
+                      scrProto->DontEnumQueryInterface());
 
         // Can't set DONT_ASK_INSTANCE_FOR_SCRIPTABLE on an instance scriptable
         // without also setting it on the class scriptable.
         MOZ_ASSERT_IF(scrWrapper->DontAskInstanceForScriptable(),
-                      sciProto.GetCallback() &&
-                      sciProto.GetCallback()->DontAskInstanceForScriptable());
+                      scrProto && scrProto->DontAskInstanceForScriptable());
 
         // Can't set CLASSINFO_INTERFACES_ONLY on an instance scriptable
         // without also setting it on the class scriptable (if present).
-        MOZ_ASSERT_IF(scrWrapper->ClassInfoInterfacesOnly() &&
-                      sciProto.GetCallback(),
-                      sciProto.GetCallback()->ClassInfoInterfacesOnly());
+        MOZ_ASSERT_IF(scrWrapper->ClassInfoInterfacesOnly() && scrProto,
+                      scrProto->ClassInfoInterfacesOnly());
 
         // Can't set ALLOW_PROP_MODS_DURING_RESOLVE on an instance scriptable
         // without also setting it on the class scriptable (if present).
-        MOZ_ASSERT_IF(scrWrapper->AllowPropModsDuringResolve() &&
-                      sciProto.GetCallback(),
-                      sciProto.GetCallback()->AllowPropModsDuringResolve());
+        MOZ_ASSERT_IF(scrWrapper->AllowPropModsDuringResolve() && scrProto,
+                      scrProto->AllowPropModsDuringResolve());
 
         // Can't set ALLOW_PROP_MODS_TO_PROTOTYPE on an instance scriptable
         // without also setting it on the class scriptable (if present).
-        MOZ_ASSERT_IF(scrWrapper->AllowPropModsToPrototype() &&
-                      sciProto.GetCallback(),
-                      sciProto.GetCallback()->AllowPropModsToPrototype());
-
-        sciWrapper.SetCallback(scrWrapper.forget());
-        return sciWrapper;
+        MOZ_ASSERT_IF(scrWrapper->AllowPropModsToPrototype() && scrProto,
+                      scrProto->AllowPropModsToPrototype());
+    } else {
+        scrWrapper = scrProto;
     }
 
-    return sciProto;
+    scrProto.forget(aScrProto);
+    scrWrapper.forget(aScrWrapper);
 }
 
 bool
-XPCWrappedNative::Init(const XPCNativeScriptableCreateInfo* sci)
+XPCWrappedNative::Init(nsIXPCScriptable* aScriptable)
 {
     AutoJSContext cx;
 
     // Setup our scriptable...
     MOZ_ASSERT(!mScriptable);
-    mScriptable = sci->GetCallback();
+    mScriptable = aScriptable;
 
     // create our flatJSObject
 
     const JSClass* jsclazz = mScriptable
                            ? mScriptable->GetJSClass()
                            : Jsvalify(&XPC_WN_NoHelper_JSClass);
 
     // We should have the global jsclass flag if and only if we're a global.
--- a/js/xpconnect/src/XPCWrappedNativeProto.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp
@@ -45,25 +45,21 @@ XPCWrappedNativeProto::~XPCWrappedNative
 #endif
 
     // Note that our weak ref to mScope is not to be trusted at this point.
 
     XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo);
 }
 
 bool
-XPCWrappedNativeProto::Init(const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
+XPCWrappedNativeProto::Init(nsIXPCScriptable* scriptable,
                             bool callPostCreatePrototype)
 {
     AutoJSContext cx;
-    nsCOMPtr<nsIXPCScriptable> callback = scriptableCreateInfo
-                                        ? scriptableCreateInfo->GetCallback()
-                                        : nullptr;
-    if (callback)
-        mScriptable = callback;
+    mScriptable = scriptable;
 
     const js::Class* jsclazz =
         (mScriptable && mScriptable->AllowPropModsToPrototype())
         ? &XPC_WN_ModsAllowed_Proto_JSClass
         : &XPC_WN_NoMods_Proto_JSClass;
 
     JS::RootedObject global(cx, mScope->GetGlobalJSObject());
     JS::RootedObject proto(cx, JS_GetObjectPrototype(cx, global));
@@ -136,17 +132,17 @@ XPCWrappedNativeProto::SystemIsBeingShut
         mJSProtoObject = nullptr;
     }
 }
 
 // static
 XPCWrappedNativeProto*
 XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
                                     nsIClassInfo* classInfo,
-                                    const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
+                                    nsIXPCScriptable* scriptable,
                                     bool callPostCreatePrototype)
 {
     AutoJSContext cx;
     MOZ_ASSERT(scope, "bad param");
     MOZ_ASSERT(classInfo, "bad param");
 
     AutoMarkingWrappedNativeProtoPtr proto(cx);
     ClassInfo2WrappedNativeProtoMap* map = nullptr;
@@ -157,17 +153,17 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCW
         return proto;
 
     RefPtr<XPCNativeSet> set = XPCNativeSet::GetNewOrUsed(classInfo);
     if (!set)
         return nullptr;
 
     proto = new XPCWrappedNativeProto(scope, classInfo, set.forget());
 
-    if (!proto || !proto->Init(scriptableCreateInfo, callPostCreatePrototype)) {
+    if (!proto || !proto->Init(scriptable, callPostCreatePrototype)) {
         delete proto.get();
         return nullptr;
     }
 
     map->Add(classInfo, proto);
 
     return proto;
 }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -828,21 +828,21 @@ nsXPConnect::GetWrappedNativePrototype(J
 {
     RootedObject aScope(aJSContext, aScopeArg);
     JSAutoCompartment ac(aJSContext, aScope);
 
     XPCWrappedNativeScope* scope = ObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    XPCNativeScriptableCreateInfo sciProto;
-    XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
+    nsCOMPtr<nsIXPCScriptable> scrProto =
+        XPCWrappedNative::GatherProtoScriptable(aClassInfo);
 
     AutoMarkingWrappedNativeProtoPtr proto(aJSContext);
-    proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, &sciProto);
+    proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, scrProto);
     if (!proto)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     JSObject* protoObj = proto->GetJSProtoObject();
     if (!protoObj)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     *aRetVal = protoObj;
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1377,47 +1377,27 @@ class XPCNativeSet final
   private:
     uint16_t                mMemberCount;
     uint16_t                mInterfaceCount;
     // Always last - object sized for array.
     // These are strong references.
     XPCNativeInterface*     mInterfaces[1];
 };
 
-/***************************************************************************/
-// XPCNativeScriptableCreateInfo is used in creating new wrapper and protos.
-// It abstracts out the scriptable interface pointer and the flags.
-
-class MOZ_STACK_CLASS XPCNativeScriptableCreateInfo final
-{
-public:
-    XPCNativeScriptableCreateInfo() {}
-
-    nsIXPCScriptable*
-    GetCallback() const {return mCallback;}
-
-    void
-    SetCallback(already_AddRefed<nsIXPCScriptable>&& callback)
-        {mCallback = callback;}
-
-private:
-    nsCOMPtr<nsIXPCScriptable>  mCallback;
-};
-
 /***********************************************/
 // XPCWrappedNativeProto hold the additional shared wrapper data
 // for XPCWrappedNative whose native objects expose nsIClassInfo.
 
 class XPCWrappedNativeProto final
 {
 public:
     static XPCWrappedNativeProto*
     GetNewOrUsed(XPCWrappedNativeScope* scope,
                  nsIClassInfo* classInfo,
-                 const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
+                 nsIXPCScriptable* scriptable,
                  bool callPostCreatePrototype = true);
 
     XPCWrappedNativeScope*
     GetScope()   const {return mScope;}
 
     XPCJSContext*
     GetContext() const {return mScope->GetContext();}
 
@@ -1472,18 +1452,17 @@ protected:
     XPCWrappedNativeProto(const XPCWrappedNativeProto& r) = delete;
     XPCWrappedNativeProto& operator= (const XPCWrappedNativeProto& r) = delete;
 
     // hide ctor
     XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
                           nsIClassInfo* ClassInfo,
                           already_AddRefed<XPCNativeSet>&& Set);
 
-    bool Init(const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
-              bool callPostCreatePrototype);
+    bool Init(nsIXPCScriptable* scriptable, bool callPostCreatePrototype);
 
 private:
 #ifdef DEBUG
     static int32_t gDEBUG_LiveProtoCount;
 #endif
 
 private:
     XPCWrappedNativeScope*   mScope;
@@ -1742,18 +1721,17 @@ public:
         TraceSelf(trc);
     }
 
     inline void SweepTearOffs();
 
     // Returns a string that shuld be free'd using JS_smprintf_free (or null).
     char* ToString(XPCWrappedNativeTearOff* to = nullptr) const;
 
-    static void GatherProtoScriptableCreateInfo(nsIClassInfo* classInfo,
-                                                XPCNativeScriptableCreateInfo& sciProto);
+    static nsIXPCScriptable* GatherProtoScriptable(nsIClassInfo* classInfo);
 
     bool HasExternalReference() const {return mRefCnt > 1;}
 
     void Suspect(nsCycleCollectionNoteRootCallback& cb);
     void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
 
     // Make ctor and dtor protected (rather than private) to placate nsCOMPtr.
 protected:
@@ -1772,32 +1750,32 @@ protected:
     void Destroy();
 
 private:
     enum {
         // Flags bits for mFlatJSObject:
         FLAT_JS_OBJECT_VALID = JS_BIT(0)
     };
 
-    bool Init(const XPCNativeScriptableCreateInfo* sci);
+    bool Init(nsIXPCScriptable* scriptable);
     bool FinishInit();
 
     bool ExtendSet(XPCNativeInterface* aInterface);
 
     nsresult InitTearOff(XPCWrappedNativeTearOff* aTearOff,
                          XPCNativeInterface* aInterface,
                          bool needJSObject);
 
     bool InitTearOffJSObject(XPCWrappedNativeTearOff* to);
 
 public:
-    static const XPCNativeScriptableCreateInfo& GatherScriptableCreateInfo(nsISupports* obj,
-                                                                           nsIClassInfo* classInfo,
-                                                                           XPCNativeScriptableCreateInfo& sciProto,
-                                                                           XPCNativeScriptableCreateInfo& sciWrapper);
+    static void GatherScriptable(nsISupports* obj,
+                                 nsIClassInfo* classInfo,
+                                 nsIXPCScriptable** scrProto,
+                                 nsIXPCScriptable** scrWrapper);
 
 private:
     union
     {
         XPCWrappedNativeScope* mMaybeScope;
         XPCWrappedNativeProto* mMaybeProto;
     };
     RefPtr<XPCNativeSet> mSet;
@@ -3178,16 +3156,20 @@ public:
     // This is only ever set during mochitest runs when enablePrivilege is called.
     // It allows the SpecialPowers scope to waive the normal chrome security
     // wrappers and expose properties directly to content. This lets us avoid a
     // bunch of overhead and complexity in our SpecialPowers automation glue.
     //
     // Using it in production is inherently unsafe.
     bool forcePermissiveCOWs;
 
+    // True if this compartment has been nuked. If true, any wrappers into or
+    // out of it should be considered invalid.
+    bool wasNuked;
+
     // Whether we've emitted a warning about a property that was filtered out
     // by a security wrapper. See XrayWrapper.cpp.
     bool wrapperDenialWarnings[WrapperDenialTypeCount];
 
     // The scriptability of this compartment.
     Scriptability scriptability;
 
     // Our XPCWrappedNativeScope. This is non-null if and only if this is an
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -352,17 +352,17 @@ bool NonVoidStringToJsval(JSContext* cx,
     nsStringBuffer* buf = str.StringBuffer();
     bool shared;
     if (!XPCStringConvert::StringBufferToJSVal(cx, buf, length, rval,
                                                &shared)) {
         return false;
     }
     if (shared) {
         // JS now needs to hold a reference to the buffer
-        buf->AddRef();
+        str.RelinquishBufferOwnership();
     }
     return true;
 }
 
 MOZ_ALWAYS_INLINE
 bool StringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
                    JS::MutableHandleValue rval)
 {
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_nuke_sandbox_event_listeners.js
@@ -0,0 +1,81 @@
+/* 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/. */
+
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=1273251
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+function promiseEvent(target, event) {
+  return new Promise(resolve => {
+    target.addEventListener(event, resolve, {capture: true, once: true});
+  });
+}
+
+add_task(function*() {
+  let principal = Services.scriptSecurityManager
+    .createCodebasePrincipalFromOrigin("http://example.com/");
+
+  let webnav = Services.appShell.createWindowlessBrowser(false);
+
+  let docShell = webnav.QueryInterface(Ci.nsIInterfaceRequestor)
+                       .getInterface(Ci.nsIDocShell);
+
+  docShell.createAboutBlankContentViewer(principal);
+
+  let window = webnav.document.defaultView;
+  let sandbox = Cu.Sandbox(window, {sandboxPrototype: window});
+
+  function sandboxContent() {
+    window.addEventListener("FromTest", () => {
+      window.dispatchEvent(new CustomEvent("FromSandbox"));
+    }, true);
+  }
+
+  Cu.evalInSandbox(`(${sandboxContent})()`, sandbox);
+
+
+  let fromTestPromise = promiseEvent(window, "FromTest");
+  let fromSandboxPromise = promiseEvent(window, "FromSandbox");
+
+  do_print("Dispatch FromTest event");
+  window.dispatchEvent(new window.CustomEvent("FromTest"));
+
+  yield fromTestPromise;
+  do_print("Got event from test");
+
+  yield fromSandboxPromise;
+  do_print("Got response from sandbox");
+
+
+  window.addEventListener("FromSandbox", () => {
+    ok(false, "Got unexpected reply from sandbox");
+  }, true);
+
+  do_print("Nuke sandbox");
+  Cu.nukeSandbox(sandbox);
+
+
+  do_print("Dispatch FromTest event");
+  fromTestPromise = promiseEvent(window, "FromTest");
+  window.dispatchEvent(new window.CustomEvent("FromTest"));
+  yield fromTestPromise;
+  do_print("Got event from test");
+
+
+  // Force cycle collection, which should cause our callback reference
+  // to be dropped, and dredge up potential issues there.
+  Cu.forceCC();
+
+
+  do_print("Dispatch FromTest event");
+  fromTestPromise = promiseEvent(window, "FromTest");
+  window.dispatchEvent(new window.CustomEvent("FromTest"));
+  yield fromTestPromise;
+  do_print("Got event from test");
+
+
+  webnav.close();
+});
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_nuke_webextension_wrappers.js
@@ -0,0 +1,75 @@
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=1273251
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+function promiseEvent(target, event) {
+  return new Promise(resolve => {
+    target.addEventListener(event, resolve, {capture: true, once: true});
+  });
+}
+
+let aps = Cc["@mozilla.org/addons/policy-service;1"].getService(Ci.nsIAddonPolicyService).wrappedJSObject;
+
+let oldAddonIdCallback = aps.setExtensionURIToAddonIdCallback(uri => uri.host);
+do_register_cleanup(() => {
+  aps.setExtensionURIToAddonIdCallback(oldAddonIdCallback);
+});
+
+function getWindowlessBrowser(url) {
+  let ssm = Services.scriptSecurityManager;
+
+  let uri = NetUtil.newURI(url);
+  // TODO: Remove when addonId origin attribute is removed.
+  let attrs = {addonId: uri.host};
+
+  let principal = ssm.createCodebasePrincipal(uri, attrs);
+
+  let webnav = Services.appShell.createWindowlessBrowser(false);
+
+  let docShell = webnav.QueryInterface(Ci.nsIInterfaceRequestor)
+                       .getInterface(Ci.nsIDocShell);
+
+  docShell.createAboutBlankContentViewer(principal);
+
+  return webnav;
+}
+
+add_task(function*() {
+  let ssm = Services.scriptSecurityManager;
+
+  let webnavA = getWindowlessBrowser("moz-extension://foo/a.html");
+  let webnavB = getWindowlessBrowser("moz-extension://foo/b.html");
+
+  let winA = Cu.waiveXrays(webnavA.document.defaultView);
+  let winB = Cu.waiveXrays(webnavB.document.defaultView);
+
+  winB.winA = winA;
+  winB.eval(`winA.thing = {foo: "bar"};`);
+
+  let getThing = winA.eval(String(() => {
+    try {
+      return thing.foo;
+    } catch (e) {
+      return String(e);
+    }
+  }));
+
+  // Check that the object can be accessed normally before windowB is closed.
+  equal(getThing(), "bar");
+
+  webnavB.close();
+
+  // Wrappers are nuked asynchronously, so wait a tick.
+  yield new Promise(resolve => setTimeout(resolve, 0));
+
+  // Check that it can't be accessed after he window has been closed.
+  let result = getThing();
+  ok(/dead object/.test(result),
+     `Result should show a dead wrapper error: ${result}`);
+
+  webnavA.close();
+});
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -92,16 +92,18 @@ fail-if = os == "android"
 [test_attributes.js]
 [test_params.js]
 [test_tearoffs.js]
 [test_want_components.js]
 [test_components.js]
 [test_allowedDomains.js]
 [test_allowedDomainsXHR.js]
 [test_nuke_sandbox.js]
+[test_nuke_sandbox_event_listeners.js]
+[test_nuke_webextension_wrappers.js]
 [test_sandbox_metadata.js]
 [test_exportFunction.js]
 [test_promise.js]
 [test_returncode.js]
 [test_textDecoder.js]
 [test_url.js]
 [test_URLSearchParams.js]
 [test_fileReader.js]
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -319,17 +319,20 @@ WrapperFactory::PrepareForWrapping(JSCon
     retObj.set(waive ? WaiveXray(cx, obj) : obj);
 }
 
 #ifdef DEBUG
 static void
 DEBUG_CheckUnwrapSafety(HandleObject obj, const js::Wrapper* handler,
                         JSCompartment* origin, JSCompartment* target)
 {
-    if (AccessCheck::isChrome(target) || xpc::IsUniversalXPConnectEnabled(target)) {
+    if (CompartmentPrivate::Get(origin)->wasNuked || CompartmentPrivate::Get(target)->wasNuked) {
+        // If either compartment has already been nuked, we should have an opaque wrapper.
+        MOZ_ASSERT(handler->hasSecurityPolicy());
+    } else if (AccessCheck::isChrome(target) || xpc::IsUniversalXPConnectEnabled(target)) {
         // If the caller is chrome (or effectively so), unwrap should always be allowed.
         MOZ_ASSERT(!handler->hasSecurityPolicy());
     } else if (CompartmentPrivate::Get(origin)->forcePermissiveCOWs) {
         // Similarly, if this is a privileged scope that has opted to make itself
         // accessible to the world (allowed only during automation), unwrap should
         // be allowed.
         MOZ_ASSERT(!handler->hasSecurityPolicy());
     } else {
@@ -438,19 +441,31 @@ WrapperFactory::Rewrap(JSContext* cx, Ha
     XrayType xrayType = GetXrayType(obj);
 
     const Wrapper* wrapper;
 
     //
     // First, handle the special cases.
     //
 
+    // If we've somehow gotten to this point after either the source or target
+    // compartment has been nuked, return an opaque wrapper to prevent further
+    // access.
+    // Ideally, we should return a DeadProxyObject instead of a wrapper in this
+    // case (bug 1322273).
+    if (CompartmentPrivate::Get(origin)->wasNuked ||
+        CompartmentPrivate::Get(target)->wasNuked) {
+        NS_WARNING("Trying to create a wrapper into or out of a nuked compartment");
+
+        wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
+    }
+
     // If UniversalXPConnect is enabled, this is just some dumb mochitest. Use
     // a vanilla CCW.
-    if (xpc::IsUniversalXPConnectEnabled(target)) {
+    else if (xpc::IsUniversalXPConnectEnabled(target)) {
         CrashIfNotInAutomation();
         wrapper = &CrossCompartmentWrapper::singleton;
     }
 
     // Let the SpecialPowers scope make its stuff easily accessible to content.
     else if (CompartmentPrivate::Get(origin)->forcePermissiveCOWs) {
         CrashIfNotInAutomation();
         wrapper = &CrossCompartmentWrapper::singleton;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..82b4d6a4372fd5a2ea9dd02e2a5032469e7dca54
GIT binary patch
literal 88332
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
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/1331339-script-extensions-shaping-1-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../fonts/TAMLThiruValluvar-Regular.ttf);
+}
+.test {
+  font-family: test;
+  width: -moz-fit-content;
+}
+.mask {
+  background: green;
+  position: relative;
+  top: -.7em;
+  height: .7em;
+}
+</style>
+</head>
+<body>
+<div class="test">
+&#x0BA4;&#x0BC6;&#x0BAA;&#x0BC6;
+<div class="mask"></div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/1331339-script-extensions-shaping-1.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url(../fonts/TAMLThiruValluvar-Regular.ttf);
+}
+.test {
+  font-family: test;
+  width: -moz-fit-content;
+}
+.mask {
+  background: green;
+  position: relative;
+  top: -.7em;
+  height: .7em;
+}
+</style>
+</head>
+<body>
+<div class="test">
+<!--
+The Grantha nukta characters U+1133C should NOT disrupt shaping of the base text.
+-->
+&#x0BA4;&#x0BC6;&#x1133c;&#x0BAA;&#x1133c;&#x0BC6;&#x1133c;
+<!--
+We place a box over the bottom of the text to mask the nuktas from reftest comparison.
+-->
+<div class="mask"></div>
+</div>
+</body>
+</html>
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -181,16 +181,17 @@ HTTP(..) != fallback-mark-stacking-1.htm
 == 726392-1.html 726392-1-ref.html
 == 726392-2.html 726392-2-ref.html
 == 726392-3.html 726392-3-ref.html
 == 745555-1.html 745555-1-ref.html
 == 745555-2.html 745555-2-ref.html
 == 820255.html 820255-ref.html
 HTTP(..) != 1170688.html 1170688-ref.html
 fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1320665-cmap-format-13.html 1320665-cmap-format-13-ref.html # see bug 1320665 comments 8-9
+HTTP(..) == 1331339-script-extensions-shaping-1.html 1331339-script-extensions-shaping-1-ref.html
 
 # ensure emoji chars don't render blank (bug 715798, bug 779042);
 # should at least render hexboxes if there's no font support
 != emoji-01.html emoji-01-notref.html
 != emoji-02.html emoji-02-notref.html
 
 # Bug 727276: tests with variation selectors 15 and 16 to control emoji rendering style
 == emoji-03.html emoji-03-ref.html
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2263,17 +2263,17 @@ nsStyleImage::ComputeActualCropRect(nsIn
 bool
 nsStyleImage::StartDecoding() const
 {
   if (mType == eStyleImageType_Image) {
     imgRequestProxy* req = GetImageData();
     if (!req) {
       return false;
     }
-    return req->StartDecodingWithResult(imgIContainer::FLAG_NONE);
+    return req->StartDecodingWithResult(imgIContainer::FLAG_ASYNC_NOTIFY);
   }
   // null image types always return false from IsComplete, so we do the same here.
   return mType != eStyleImageType_Null ? true : false;
 }
 
 bool
 nsStyleImage::IsOpaque() const
 {
--- a/media/webrtc/signaling/src/common/EncodingConstraints.h
+++ b/media/webrtc/signaling/src/common/EncodingConstraints.h
@@ -37,16 +37,28 @@ public:
       maxBr == constraints.maxBr &&
       maxPps == constraints.maxPps &&
       maxMbps == constraints.maxMbps &&
       maxCpb == constraints.maxCpb &&
       maxDpb == constraints.maxDpb &&
       scaleDownBy == constraints.scaleDownBy;
   }
 
+  /**
+   * This returns true if the constraints affecting resolution are equal.
+   */
+  bool ResolutionEquals(const EncodingConstraints& constraints) const
+  {
+    return
+      maxWidth == constraints.maxWidth &&
+      maxHeight == constraints.maxHeight &&
+      maxFs == constraints.maxFs &&
+      scaleDownBy == constraints.scaleDownBy;
+  }
+
   uint32_t maxWidth;
   uint32_t maxHeight;
   uint32_t maxFps;
   uint32_t maxFs;
   uint32_t maxBr;
   uint32_t maxPps;
   uint32_t maxMbps; // macroblocks per second
   uint32_t maxCpb; // coded picture buffer size
--- a/media/webrtc/signaling/src/jsep/JsepTrack.cpp
+++ b/media/webrtc/signaling/src/jsep/JsepTrack.cpp
@@ -256,16 +256,19 @@ JsepTrack::FindConstraints(const std::st
 }
 
 void
 JsepTrack::CreateEncodings(
     const SdpMediaSection& remote,
     const std::vector<JsepCodecDescription*>& negotiatedCodecs,
     JsepTrackNegotiatedDetails* negotiatedDetails)
 {
+  negotiatedDetails->mTias = remote.GetBandwidth("TIAS");
+  // TODO add support for b=AS if TIAS is not set (bug 976521)
+
   std::vector<SdpRidAttributeList::Rid> rids;
   GetRids(remote, sdp::kRecv, &rids); // Get rids we will send
   NegotiateRids(rids, &mJsEncodeConstraints);
   if (rids.empty()) {
     // Add dummy value with an empty id to make sure we get a single unicast
     // stream.
     rids.push_back(SdpRidAttributeList::Rid());
   }
@@ -289,18 +292,16 @@ JsepTrack::CreateEncodings(
     // If we end up supporting params for rid, we would handle that here.
 
     // Incorporate the corresponding JS encoding constraints, if they exist
     for (const JsConstraints& jsConstraints : mJsEncodeConstraints) {
       if (jsConstraints.rid == rids[i].id) {
         encoding->mConstraints = jsConstraints.constraints;
       }
     }
-
-    encoding->UpdateMaxBitrate(remote);
   }
 }
 
 std::vector<JsepCodecDescription*>
 JsepTrack::GetCodecClones() const
 {
   std::vector<JsepCodecDescription*> clones;
   for (const JsepCodecDescription* codec : mPrototypeCodecs.values) {
--- a/media/webrtc/signaling/src/jsep/JsepTrack.h
+++ b/media/webrtc/signaling/src/jsep/JsepTrack.h
@@ -24,16 +24,20 @@
 #include "signaling/src/sdp/SdpMediaSection.h"
 #include "signaling/src/common/PtrVector.h"
 
 namespace mozilla {
 
 class JsepTrackNegotiatedDetails
 {
 public:
+  JsepTrackNegotiatedDetails() :
+    mTias(0)
+  {}
+
   size_t
   GetEncodingCount() const
   {
     return mEncodings.values.size();
   }
 
   const JsepTrackEncoding&
   GetEncoding(size_t index) const
@@ -61,22 +65,28 @@ public:
     }
   }
 
   std::vector<uint8_t> GetUniquePayloadTypes() const
   {
     return mUniquePayloadTypes;
   }
 
+  uint32_t GetTias() const
+  {
+    return mTias;
+  }
+
 private:
   friend class JsepTrack;
 
   std::map<std::string, SdpExtmapAttributeList::Extmap> mExtmap;
   std::vector<uint8_t> mUniquePayloadTypes;
   PtrVector<JsepTrackEncoding> mEncodings;
+  uint32_t mTias; // bits per second
 };
 
 class JsepTrack
 {
 public:
   JsepTrack(mozilla::SdpMediaSection::MediaType type,
             const std::string& streamid,
             const std::string& trackid,
--- a/media/webrtc/signaling/src/jsep/JsepTrackEncoding.h
+++ b/media/webrtc/signaling/src/jsep/JsepTrackEncoding.h
@@ -34,26 +34,16 @@ public:
     for (const JsepCodecDescription* codec : mCodecs.values) {
       if (codec->mDefaultPt == format) {
         return true;
       }
     }
     return false;
   }
 
-  void UpdateMaxBitrate(const SdpMediaSection& remote)
-  {
-    uint32_t tias = remote.GetBandwidth("TIAS");
-    // select minimum of the two which is not zero
-    mConstraints.maxBr = std::min(tias ? tias : mConstraints.maxBr,
-                                  mConstraints.maxBr ? mConstraints.maxBr :
-                                                       tias);
-    // TODO add support for b=AS if TIAS is not set (bug 976521)
-  }
-
   EncodingConstraints mConstraints;
   std::string mRid;
 
 private:
   PtrVector<JsepCodecDescription> mCodecs;
 };
 }
 
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.h
@@ -191,16 +191,20 @@ public:
   webrtc::VoiceEngine* GetVoiceEngine() { return mVoiceEngine; }
 
   /* Set Local SSRC list.
    * Note: Until the refactor of the VoE into the call API is complete
    *   this list should contain only a single ssrc.
    */
   bool SetLocalSSRCs(const std::vector<unsigned int>& aSSRCs) override;
   std::vector<unsigned int> GetLocalSSRCs() const override;
+  bool SetRemoteSSRC(unsigned int ssrc) override
+  {
+    return false;
+  }
   bool GetRemoteSSRC(unsigned int* ssrc) override;
   bool SetLocalCNAME(const char* cname) override;
   bool GetVideoEncoderStats(double* framerateMean,
                             double* framerateStdDev,
                             double* bitrateMean,
                             double* bitrateStdDev,
                             uint32_t* droppedFrames) override
   {
--- a/media/webrtc/signaling/src/media-conduit/CodecConfig.h
+++ b/media/webrtc/signaling/src/media-conduit/CodecConfig.h
@@ -85,16 +85,17 @@ public:
   std::vector<std::string> mAckFbTypes;
   std::vector<std::string> mNackFbTypes;
   std::vector<std::string> mCcmFbTypes;
   // Don't pass mOtherFbTypes from JsepVideoCodecDescription because we'd have
   // to drag SdpRtcpFbAttributeList::Feedback along too.
   bool mRembFbSet;
   bool mFECFbSet;
 
+  uint32_t mTias;
   EncodingConstraints mEncodingConstraints;
   struct SimulcastEncoding {
     std::string rid;
     EncodingConstraints constraints;
     bool operator==(const SimulcastEncoding& aOther) const {
       return rid == aOther.rid &&
         constraints == aOther.constraints;
     }
@@ -110,16 +111,17 @@ public:
   bool operator==(const VideoCodecConfig& aRhs) const {
     if (mType != aRhs.mType ||
         mName != aRhs.mName ||
         mAckFbTypes != aRhs.mAckFbTypes ||
         mNackFbTypes != aRhs.mNackFbTypes ||
         mCcmFbTypes != aRhs.mCcmFbTypes ||
         mRembFbSet != aRhs.mRembFbSet ||
         mFECFbSet != aRhs.mFECFbSet ||
+        mTias != aRhs.mTias ||
         !(mEncodingConstraints == aRhs.mEncodingConstraints) ||
         !(mSimulcastEncodings == aRhs.mSimulcastEncodings) ||
         mSpropParameterSets != aRhs.mSpropParameterSets ||
         mProfile != aRhs.mProfile ||
         mConstraints != aRhs.mConstraints ||
         mLevel != aRhs.mLevel ||
         mPacketizationMode != aRhs.mPacketizationMode) {
       return false;
@@ -130,31 +132,46 @@ public:
 
   VideoCodecConfig(int type,
                    std::string name,
                    const EncodingConstraints& constraints,
                    const struct VideoCodecConfigH264 *h264 = nullptr) :
     mType(type),
     mName(name),
     mFECFbSet(false),
+    mTias(0),
     mEncodingConstraints(constraints),
     mProfile(0x42),
     mConstraints(0xE0),
     mLevel(0x0C),
     mPacketizationMode(1)
   {
     if (h264) {
       mProfile = (h264->profile_level_id & 0x00FF0000) >> 16;
       mConstraints = (h264->profile_level_id & 0x0000FF00) >> 8;
       mLevel = (h264->profile_level_id & 0x000000FF);
       mPacketizationMode = h264->packetization_mode;
       mSpropParameterSets = h264->sprop_parameter_sets;
     }
   }
 
+  bool ResolutionEquals(const VideoCodecConfig& aConfig) const
+  {
+    if (mSimulcastEncodings.size() != aConfig.mSimulcastEncodings.size()) {
+      return false;
+    }
+    for (size_t i = 0; i < mSimulcastEncodings.size(); ++i) {
+      if (!mSimulcastEncodings[i].constraints.ResolutionEquals(
+            aConfig.mSimulcastEncodings[i].constraints)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   // Nothing seems to use this right now. Do we intend to support this
   // someday?
   bool RtcpFbAckIsSet(const std::string& type) const
   {
     for (auto i = mAckFbTypes.begin(); i != mAckFbTypes.end(); ++i) {
       if (*i == type) {
         return true;
       }
--- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
+++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
@@ -240,16 +240,17 @@ public:
   /* Sets the local SSRCs
    * @return true iff the local ssrcs == aSSRCs upon return
    * Note: this is an ordered list and {a,b,c} != {b,a,c}
    */
   virtual bool SetLocalSSRCs(const std::vector<unsigned int>& aSSRCs) = 0;
   virtual std::vector<unsigned int> GetLocalSSRCs() const = 0;
 
   virtual bool GetRemoteSSRC(unsigned int* ssrc) = 0;
+  virtual bool SetRemoteSSRC(unsigned int ssrc) = 0;
   virtual bool SetLocalCNAME(const char* cname) = 0;
 
   /**
    * Functions returning stats needed by w3c stats model.
    */
   virtual bool GetVideoEncoderStats(double* framerateMean,
                                     double* framerateStdDev,
                                     double* bitrateMean,
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -73,17 +73,17 @@ static const char* kRedPayloadName = "re
 // Convert (SI) kilobits/sec to (SI) bits/sec
 #define KBPS(kbps) kbps * 1000
 const uint32_t WebrtcVideoConduit::kDefaultMinBitrate_bps =  KBPS(200);
 const uint32_t WebrtcVideoConduit::kDefaultStartBitrate_bps = KBPS(300);
 const uint32_t WebrtcVideoConduit::kDefaultMaxBitrate_bps = KBPS(2000);
 
 // 32 bytes is what WebRTC CodecInst expects
 const unsigned int WebrtcVideoConduit::CODEC_PLNAME_SIZE = 32;
-static const unsigned int kViEMinCodecBitrate = 30;
+static const int kViEMinCodecBitrate = 30;
 
 template<typename T>
 T MinIgnoreZero(const T& a, const T& b)
 {
   return std::min(a? a:b, b? b:a);
 }
 
 void
@@ -403,16 +403,17 @@ WebrtcVideoConduit::DeleteRecvStream()
 
 MediaConduitErrorCode
 WebrtcVideoConduit::CreateRecvStream()
 {
   webrtc::VideoReceiveStream::Decoder decoder_desc;
   std::unique_ptr<webrtc::VideoDecoder> decoder;
   webrtc::VideoDecoder::DecoderType decoder_type;
 
+  mRecvStreamConfig.decoders.clear();
   for (auto& config : mRecvCodecList) {
     decoder_type = PayloadNameToDecoderType(config->mName);
     if (decoder_type == webrtc::VideoDecoder::DecoderType::kUnsupportedCodec) {
       CSFLogError(logTag, "%s Unknown decoder type: %s", __FUNCTION__,
                   config->mName.c_str());
       continue;
     }
 
@@ -512,74 +513,98 @@ WebrtcVideoConduit::ConfigureSendMediaCo
   unsigned short width = 320;
   unsigned short height = 240;
   int max_framerate;
   if (codecConfig->mEncodingConstraints.maxFps > 0) {
     max_framerate = codecConfig->mEncodingConstraints.maxFps;
   } else {
     max_framerate = DEFAULT_VIDEO_MAX_FRAMERATE;
   }
+  // apply restrictions from maxMbps/etc
+  mSendingFramerate = SelectSendFrameRate(codecConfig,
+                                          max_framerate,
+                                          mSendingWidth,
+                                          mSendingHeight);
+
+  // So we can comply with b=TIAS/b=AS/maxbr=X when input resolution changes
+  mNegotiatedMaxBitrate = codecConfig->mTias / 1000;
 
   // width/height will be overridden on the first frame; they must be 'sane' for
   // SetSendCodec()
 
   if (mSendingWidth != 0) {
     // We're already in a call and are reconfiguring (perhaps due to
-    // ReplaceTrack).  Set to match the last frame we sent.
+    // ReplaceTrack).
+    bool resolutionChanged;
+    {
+      MutexAutoLock lock(mCodecMutex);
+      resolutionChanged = !mCurSendCodecConfig->ResolutionEquals(*codecConfig);
+    }
 
-    // We could also set mLastWidth to 0, to force immediate reconfig -
-    // more expensive, but perhaps less risk of missing something.  Really
-    // on ReplaceTrack we should just call ConfigureCodecMode(), and if the
-    // mode changed, we re-configure.
-    width = mSendingWidth;
-    height = mSendingHeight;
-    // max framerate remains the same
+    if (resolutionChanged) {
+      // We're already in a call and due to renegotiation an encoder parameter
+      // that requires reconfiguration has changed. Resetting these members
+      // triggers reconfig on the next frame.
+      mLastWidth = 0;
+      mLastHeight = 0;
+      mSendingWidth = 0;
+      mSendingHeight = 0;
+    } else {
+      // We're already in a call but changes don't require a reconfiguration.
+      // We update the resolutions in the send codec to match the current
+      // settings.  Framerate is already set.
+      width = mSendingWidth;
+      height = mSendingHeight;
+      // Bitrates are set in the loop below
+    }
   }
-  mSendingFramerate = std::max(mSendingFramerate,
-                               static_cast<unsigned int>(max_framerate));
-
-  // So we can comply with b=TIAS/b=AS/maxbr=X when input resolution changes
-  // XXX not sure this is right!
-  // XXX mNegotiatedMaxBitrate = MinIgnoreZero(mPrefMaxBitrate, codecConfig->maxBitrate);
 
   for (size_t idx = streamCount - 1; streamCount > 0; idx--, streamCount--) {
     webrtc::VideoStream video_stream;
     VideoEncoderConfigBuilder::SimulcastStreamConfig simulcast_config;
     // Stream dimensions must be divisable by 2^(n-1), where n is the number of layers.
     // Each lower resolution layer is 1/2^(n-1) of the size of largest layer,
     // where n is the number of the layer
 
     // width/height will be overridden on the first frame; they must be 'sane' for
     // SetSendCodec()
     video_stream.width = width >> idx;
     video_stream.height = height >> idx;
-    video_stream.max_framerate = max_framerate;
+    video_stream.max_framerate = mSendingFramerate;
     auto& simulcastEncoding = codecConfig->mSimulcastEncodings[idx];
     // leave vector temporal_layer_thresholds_bps empty
     video_stream.temporal_layer_thresholds_bps.clear();
+    // Calculate these first
     video_stream.max_bitrate_bps = MinIgnoreZero(simulcastEncoding.constraints.maxBr,
                                                  kDefaultMaxBitrate_bps);
     video_stream.max_bitrate_bps = MinIgnoreZero((int) mPrefMaxBitrate*1000,
                                                  video_stream.max_bitrate_bps);
     video_stream.min_bitrate_bps = (mMinBitrate ? mMinBitrate : kDefaultMinBitrate_bps);
     if (video_stream.min_bitrate_bps > video_stream.max_bitrate_bps) {
       video_stream.min_bitrate_bps = video_stream.max_bitrate_bps;
     }
     video_stream.target_bitrate_bps = (mStartBitrate ? mStartBitrate : kDefaultStartBitrate_bps);
     if (video_stream.target_bitrate_bps > video_stream.max_bitrate_bps) {
       video_stream.target_bitrate_bps = video_stream.max_bitrate_bps;
     }
     if (video_stream.target_bitrate_bps < video_stream.min_bitrate_bps) {
       video_stream.target_bitrate_bps = video_stream.min_bitrate_bps;
     }
+    // We should use SelectBitrates here for the case of already-sending and no reconfig needed;
+    // overrides the calculations above
+    if (mSendingWidth) { // cleared if we need a reconfig
+      SelectBitrates(video_stream.width, video_stream.height,
+                     simulcastEncoding.constraints.maxBr,
+                     mLastFramerateTenths, video_stream);
+    }
 
     video_stream.max_qp = kQpMax;
     video_stream.SetRid(simulcastEncoding.rid);
     simulcast_config.jsScaleDownBy = simulcastEncoding.constraints.scaleDownBy;
-    simulcast_config.jsMaxBitrate = simulcastEncoding.constraints.maxBr;
+    simulcast_config.jsMaxBitrate = simulcastEncoding.constraints.maxBr; // bps
 
     if (codecConfig->mName == "H264") {
       if (codecConfig->mEncodingConstraints.maxMbps > 0) {
         // Not supported yet!
         CSFLogError(logTag, "%s H.264 max_mbps not supported yet", __FUNCTION__);
       }
     }
     mEncoderConfig.AddStream(video_stream, simulcast_config);
@@ -663,16 +688,22 @@ WebrtcVideoConduit::SetRemoteSSRC(unsign
     return true;
   }
 
   if (StopReceiving() != kMediaConduitNoError) {
     return false;
   }
 
   DeleteRecvStream();
+  MediaConduitErrorCode rval = CreateRecvStream();
+  if (rval != kMediaConduitNoError) {
+    CSFLogError(logTag, "%s Start Receive Error %d ", __FUNCTION__, rval);
+    return false;
+  }
+
   return (StartReceiving() == kMediaConduitNoError);
 }
 
 bool
 WebrtcVideoConduit::GetRemoteSSRC(unsigned int* ssrc)
 {
   {
     MutexAutoLock lock(mCodecMutex);
@@ -840,17 +871,16 @@ WebrtcVideoConduit::InitMain()
          mStartBitrate = temp;
          }
       }
       if (!NS_WARN_IF(NS_FAILED(branch->GetIntPref(
             "media.peerconnection.video.max_bitrate", &temp))))
       {
         if (temp >= 0) {
           mPrefMaxBitrate = temp;
-          mNegotiatedMaxBitrate = temp; // simplifies logic in SelectBitrate (don't have to do two limit tests)
         }
       }
       if (mMinBitrate != 0 && mMinBitrate < kViEMinCodecBitrate) {
         mMinBitrate = kViEMinCodecBitrate;
       }
       if (mStartBitrate < mMinBitrate) {
         mStartBitrate = mMinBitrate;
       }
@@ -1079,18 +1109,18 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
   // Now decide if we need to recreate the receive stream, or can keep it
   if (!mRecvStream ||
       CodecsDifferent(recv_codecs, mRecvCodecList) ||
       mRecvStreamConfig.rtp.nack.rtp_history_ms != (use_nack_basic ? 1000 : 0) ||
       mRecvStreamConfig.rtp.remb != use_remb ||
       mRecvStreamConfig.rtp.tmmbr != use_tmmbr ||
       mRecvStreamConfig.rtp.keyframe_method != kf_request_method ||
       (use_fec &&
-       mRecvStreamConfig.rtp.fec.ulpfec_payload_type != ulpfec_payload_type ||
-       mRecvStreamConfig.rtp.fec.red_payload_type != red_payload_type)) {
+       (mRecvStreamConfig.rtp.fec.ulpfec_payload_type != ulpfec_payload_type ||
+        mRecvStreamConfig.rtp.fec.red_payload_type != red_payload_type))) {
 
     condError = StopReceiving();
     if (condError != kMediaConduitNoError) {
       return condError;
     }
 
     // If we fail after here things get ugly
     mRecvStreamConfig.rtp.rtcp_mode = webrtc::RtcpMode::kCompound;
@@ -1114,26 +1144,30 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
     auto ssrc = mRecvStreamConfig.rtp.remote_ssrc;
     do {
       SECStatus rv = PK11_GenerateRandom(reinterpret_cast<unsigned char*>(&ssrc), sizeof(ssrc));
       if (rv != SECSuccess) {
         return kMediaConduitUnknownError;
       }
     } while (ssrc == mRecvStreamConfig.rtp.remote_ssrc);
 
-    //DEBUG(pkerr)  mRecvStreamConfig.rtp.local_ssrc = ssrc;
-    mRecvStreamConfig.rtp.local_ssrc = 1;
+    mRecvStreamConfig.rtp.local_ssrc = ssrc;
 
     // XXX Copy over those that are the same and don't rebuild them
     mRecvCodecList.SwapElements(recv_codecs);
     recv_codecs.Clear();
-    mRecvStreamConfig.decoders.clear();
     mRecvStreamConfig.rtp.rtx.clear();
     // Rebuilds mRecvStream from mRecvStreamConfig
     DeleteRecvStream();
+    MediaConduitErrorCode rval = CreateRecvStream();
+    if (rval != kMediaConduitNoError) {
+      CSFLogError(logTag, "%s Start Receive Error %d ", __FUNCTION__, rval);
+      return rval;
+    }
+
     return StartReceiving();
   }
   return kMediaConduitNoError;
 }
 
 webrtc::VideoDecoder*
 WebrtcVideoConduit::CreateDecoder(webrtc::VideoDecoder::DecoderType aType)
 {
@@ -1241,20 +1275,20 @@ WebrtcVideoConduit::CreateEncoder(webrtc
     encoder = webrtc::VideoEncoder::Create(aType, enable_simulcast);
   }
 
   return encoder;
 }
 
 struct ResolutionAndBitrateLimits
 {
-  uint32_t resolution_in_mb;
-  uint32_t min_bitrate_bps;
-  uint32_t start_bitrate_bps;
-  uint32_t max_bitrate_bps;
+  int resolution_in_mb;
+  int min_bitrate_bps;
+  int start_bitrate_bps;
+  int max_bitrate_bps;
 };
 
 #define MB_OF(w,h) ((unsigned int)((((w+15)>>4))*((unsigned int)((h+15)>>4))))
 // For now, try to set the max rates well above the knee in the curve.
 // Chosen somewhat arbitrarily; it's hard to find good data oriented for
 // realtime interactive/talking-head recording.  These rates assume
 // 30fps.
 
@@ -1266,61 +1300,61 @@ static ResolutionAndBitrateLimits kResol
   {MB_OF(800, 480), KBPS(600), KBPS(800), KBPS(2500)}, // HD ~720
   {tl::Max<MB_OF(400, 240), MB_OF(352, 288)>::value, KBPS(200), KBPS(300), KBPS(1300)}, // VGA, WVGA
   {MB_OF(176, 144), KBPS(100), KBPS(150), KBPS(500)}, // WQVGA, CIF
   {0 , KBPS(40), KBPS(80), KBPS(250)} // QCIF and below
 };
 
 void
 WebrtcVideoConduit::SelectBitrates(
-  unsigned short width, unsigned short height, uint32_t cap,
+  unsigned short width, unsigned short height, int cap,
   int32_t aLastFramerateTenths,
   webrtc::VideoStream& aVideoStream)
 {
   int& out_min = aVideoStream.min_bitrate_bps;
   int& out_start = aVideoStream.target_bitrate_bps;
   int& out_max = aVideoStream.max_bitrate_bps;
   // max bandwidth should be proportional (not linearly!) to resolution, and
   // proportional (perhaps linearly, or close) to current frame rate.
-  unsigned int fs = MB_OF(width, height);
+  int fs = MB_OF(width, height);
 
   for (ResolutionAndBitrateLimits resAndLimits : kResolutionAndBitrateLimits) {
     if (fs > resAndLimits.resolution_in_mb &&
         // pick the highest range where at least start rate is within cap
         // (or if we're at the end of the array).
         (!cap || resAndLimits.start_bitrate_bps <= cap ||
          resAndLimits.resolution_in_mb == 0)) {
-      out_min = static_cast<int>(MinIgnoreZero(resAndLimits.min_bitrate_bps, cap));
-      out_start = static_cast<int>(MinIgnoreZero(resAndLimits.start_bitrate_bps, cap));
-      out_max = static_cast<int>(MinIgnoreZero(resAndLimits.max_bitrate_bps, cap));
+      out_min = MinIgnoreZero(resAndLimits.min_bitrate_bps, cap);
+      out_start = MinIgnoreZero(resAndLimits.start_bitrate_bps, cap);
+      out_max = MinIgnoreZero(resAndLimits.max_bitrate_bps, cap);
       break;
     }
   }
 
   // mLastFramerateTenths is scaled by *10
   double framerate = std::min((aLastFramerateTenths / 10.), 60.0);
   MOZ_ASSERT(framerate > 0);
   // Now linear reduction/increase based on fps (max 60fps i.e. doubling)
   if (framerate >= 10) {
     out_min = out_min * (framerate / 30);
     out_start = out_start * (framerate / 30);
-    out_max = std::max(static_cast<unsigned int>(out_max * (framerate / 30)), cap);
+    out_max = std::max(static_cast<int>(out_max * (framerate / 30)), cap);
   } else {
     // At low framerates, don't reduce bandwidth as much - cut slope to 1/2.
     // Mostly this would be ultra-low-light situations/mobile or screensharing.
     out_min = out_min * ((10 - (framerate / 2)) / 30);
     out_start = out_start * ((10 - (framerate / 2)) / 30);
-    out_max = std::max(static_cast<unsigned int>(out_max * ((10 - (framerate / 2)) / 30)), cap);
+    out_max = std::max(static_cast<int>(out_max * ((10 - (framerate / 2)) / 30)), cap);
   }
 
   if (mMinBitrate && mMinBitrate > out_min) {
     out_min = mMinBitrate;
   }
   // If we try to set a minimum bitrate that is too low, ViE will reject it.
-  out_min = std::max(static_cast<int>(kViEMinCodecBitrate), out_min);
+  out_min = std::max(kViEMinCodecBitrate, out_min);
   if (mStartBitrate && mStartBitrate > out_start) {
     out_start = mStartBitrate;
   }
   out_start = std::max(out_start, out_min);
 
   // Note: mNegotiatedMaxBitrate is the max transport bitrate - it applies to
   // a single codec encoding, but should also apply to the sum of all
   // simulcast layers in this encoding!  So sum(layers.maxBitrate) <=
@@ -1448,18 +1482,20 @@ WebrtcVideoConduit::SelectSendResolution
     // This will avoid us continually retrying this operation if it fails.
     // If the resolution changes, we'll try again.  In the meantime, we'll
     // keep using the old size in the encoder.
     mSendingWidth = width;
     mSendingHeight = height;
     changed = true;
   }
 
-  // uses mSendingWidth/Height
-  unsigned int framerate = SelectSendFrameRate(mSendingFramerate);
+  unsigned int framerate = SelectSendFrameRate(mCurSendCodecConfig,
+                                               mSendingFramerate,
+                                               mSendingWidth,
+                                               mSendingHeight);
   if (mSendingFramerate != framerate) {
     CSFLogDebug(logTag, "%s: framerate changing to %u (from %u)",
                 __FUNCTION__, framerate, mSendingFramerate);
     mSendingFramerate = framerate;
     changed = true;
   }
 
   if (changed) {
@@ -1523,27 +1559,30 @@ WebrtcVideoConduit::ReconfigureSendCodec
     [&](webrtc::VideoStream& video_stream,
         VideoEncoderConfigBuilder::SimulcastStreamConfig& simStream,
         const size_t index)
   {
     mInReconfig = false;
 
     CSFLogDebug(logTag,
                 "%s: Requesting resolution change to %ux%u (from %ux%u), jsScaleDownBy=%f",
-                __FUNCTION__, width, height, (unsigned int)video_stream.width,
-                (unsigned int)video_stream.height, simStream.jsScaleDownBy);
+                __FUNCTION__, width, height, static_cast<unsigned int>(video_stream.width),
+                static_cast<unsigned int>(video_stream.height), simStream.jsScaleDownBy);
 
     MOZ_ASSERT(simStream.jsScaleDownBy >= 1.0);
     uint32_t new_width = (width / simStream.jsScaleDownBy);
     uint32_t new_height = (height / simStream.jsScaleDownBy);
     video_stream.width = width;
     video_stream.height = height;
+    // XXX this should depend on the final values (below) of video_stream.width/height, not
+    // the current value calculated on the incoming framesize (largest simulcast layer)
     video_stream.max_framerate = mSendingFramerate;
-    unsigned int out_min, out_start, out_max;
-    SelectBitrates(video_stream.width, video_stream.height, 0,
+    SelectBitrates(video_stream.width, video_stream.height,
+                   // XXX formerly was MinIgnoreZero(mNegotiatedMaxBitrate, simStream.jsMaxBitrate),
+                   simStream.jsMaxBitrate,
                    mLastFramerateTenths, video_stream);
     CSFLogVerbose(logTag, "%s: new_width=%" PRIu32 " new_height=%" PRIu32,
                   __FUNCTION__, new_width, new_height);
     if (new_width != video_stream.width || new_height != video_stream.height) {
       if (mEncoderConfig.StreamCount() == 1) {
         CSFLogVerbose(logTag, "%s: ConstrainPreservingAspectRatio", __FUNCTION__);
         // Use less strict scaling in unicast. That way 320x240 / 3 = 106x79.
         ConstrainPreservingAspectRatio(new_width, new_height,
@@ -1554,57 +1593,53 @@ WebrtcVideoConduit::ReconfigureSendCodec
         // is exactly the same aspect ratio. 320x240 / 3 = 80x60.
         ConstrainPreservingAspectRatioExact(new_width * new_height,
                                             &video_stream.width, &video_stream.height);
       }
     }
 
     CSFLogDebug(
       logTag, "%s: Encoder resolution changed to %ux%u @ %ufps, bitrate %u:%u",
-      __FUNCTION__, video_stream.width, video_stream.height, mSendingFramerate,
+      __FUNCTION__, static_cast<unsigned int>(video_stream.width),
+      static_cast<unsigned int>(video_stream.height), mSendingFramerate,
       video_stream.min_bitrate_bps, video_stream.max_bitrate_bps);
   });
   if (!mSendStream->ReconfigureVideoEncoder(mEncoderConfig.GenerateConfig())) {
     CSFLogError(logTag, "%s: ReconfigureVideoEncoder failed", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
   if (frame) {
     // XXX I really don't like doing this from MainThread...
     mSendStream->Input()->IncomingCapturedFrame(*frame);
     CSFLogDebug(logTag, "%s Inserted a frame from reconfig lambda", __FUNCTION__);
   }
   return NS_OK;
 }
 
-// Invoked under lock of mCodecMutex!
 unsigned int
-WebrtcVideoConduit::SelectSendFrameRate(unsigned int framerate) const
+WebrtcVideoConduit::SelectSendFrameRate(const VideoCodecConfig* codecConfig,
+                                        unsigned int old_framerate,
+                                        unsigned short sending_width,
+                                        unsigned short sending_height) const
 {
-  mCodecMutex.AssertCurrentThreadOwns();
-  unsigned int new_framerate = framerate;
+  unsigned int new_framerate = old_framerate;
 
   // Limit frame rate based on max-mbps
-  if (mCurSendCodecConfig && mCurSendCodecConfig->mEncodingConstraints.maxMbps)
+  if (codecConfig && codecConfig->mEncodingConstraints.maxMbps)
   {
-    unsigned int cur_fs, mb_width, mb_height, max_fps;
+    unsigned int cur_fs, mb_width, mb_height;
 
-    mb_width = (mSendingWidth + 15) >> 4;
-    mb_height = (mSendingHeight + 15) >> 4;
+    mb_width = (sending_width + 15) >> 4;
+    mb_height = (sending_height + 15) >> 4;
 
     cur_fs = mb_width * mb_height;
     if (cur_fs > 0) { // in case no frames have been sent
-      max_fps = mCurSendCodecConfig->mEncodingConstraints.maxMbps / cur_fs;
-      if (max_fps < mSendingFramerate) {
-        new_framerate = max_fps;
-      }
+      new_framerate = codecConfig->mEncodingConstraints.maxMbps / cur_fs;
 
-      if (mCurSendCodecConfig->mEncodingConstraints.maxFps != 0 &&
-          mCurSendCodecConfig->mEncodingConstraints.maxFps < mSendingFramerate) {
-        new_framerate = mCurSendCodecConfig->mEncodingConstraints.maxFps;
-      }
+      new_framerate = MinIgnoreZero(new_framerate, codecConfig->mEncodingConstraints.maxFps);
     }
   }
   return new_framerate;
 }
 
 MediaConduitErrorCode
 WebrtcVideoConduit::SendVideoFrame(unsigned char* video_buffer,
                                    unsigned int video_length,
@@ -1668,17 +1703,17 @@ WebrtcVideoConduit::SendVideoFrame(webrt
 }
 
 // Transport Layer Callbacks
 
 MediaConduitErrorCode
 WebrtcVideoConduit::DeliverPacket(const void* data, int len)
 {
   // Media Engine should be receiving already.
-  if (/* XXX Remove this.... !mEngineReceiving ||*/ !mCall) {
+  if (!mCall) {
     CSFLogError(logTag, "Error: %s when not receiving", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
   // XXX we need to get passed the time the packet was received
   webrtc::PacketReceiver::DeliveryStatus status =
     mCall->Call()->Receiver()->DeliverPacket(webrtc::MediaType::VIDEO,
                                              static_cast<const uint8_t*>(data),
@@ -1783,24 +1818,17 @@ WebrtcVideoConduit::StartReceiving()
   if (mEngineReceiving) {
     return kMediaConduitNoError;
   }
 
   CSFLogDebug(logTag, "%s Attemping to start... ", __FUNCTION__);
   {
     // Start Receive on the video engine
     MutexAutoLock lock(mCodecMutex);
-
-    if (!mRecvStream) {
-      MediaConduitErrorCode rval = CreateRecvStream();
-      if (rval != kMediaConduitNoError) {
-        CSFLogError(logTag, "%s Start Receive Error %d ", __FUNCTION__, rval);
-        return rval;
-      }
-    }
+    MOZ_ASSERT(mRecvStream);
 
     mRecvStream->Start();
     mEngineReceiving = true;
   }
 
   return kMediaConduitNoError;
 }
 
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -154,17 +154,17 @@ public:
    * Function to set the encoding bitrate limits based on incoming frame size and rate
    * @param width, height: dimensions of the frame
    * @param cap: user-enforced max bitrate, or 0
    * @param aLastFramerateTenths: holds the current input framerate
    * @param aVideoStream stream to apply bitrates to
    */
   void SelectBitrates(unsigned short width,
                       unsigned short height,
-                      unsigned int cap,
+                      int cap,
                       int32_t aLastFramerateTenths,
                       webrtc::VideoStream& aVideoStream);
 
   /**
    * Function to select and change the encoding resolution based on incoming frame size
    * and current available bandwidth.
    * @param width, height: dimensions of the frame
    * @param frame: optional frame to submit for encoding after reconfig
@@ -184,17 +184,20 @@ public:
                                 webrtc::VideoFrame* frame);
 
   /**
    * Function to select and change the encoding frame rate based on incoming frame rate
    * and max-mbps setting.
    * @param current framerate
    * @result new framerate
    */
-  unsigned int SelectSendFrameRate(unsigned int framerate) const;
+  unsigned int SelectSendFrameRate(const VideoCodecConfig* codecConfig,
+                                   unsigned int old_framerate,
+                                   unsigned short sending_width,
+                                   unsigned short sending_height) const;
 
   /**
    * Function to deliver a capture video frame for encoding and transport
    * @param video_frame: pointer to captured video-frame.
    * @param video_frame_length: size of the frame
    * @param width, height: dimensions of the frame
    * @param video_type: Type of the video frame - I420, RAW
    * @param captured_time: timestamp when the frame was captured.
@@ -458,21 +461,21 @@ private:
   unsigned short mReceivingWidth;
   unsigned short mReceivingHeight;
   unsigned int   mSendingFramerate;
   // scaled by *10 because Atomic<double/float> isn't supported
   mozilla::Atomic<int32_t, mozilla::Relaxed> mLastFramerateTenths;
   unsigned short mNumReceivingStreams;
   bool mVideoLatencyTestEnable;
   uint64_t mVideoLatencyAvg;
-  uint32_t mMinBitrate;
-  uint32_t mStartBitrate;
-  uint32_t mPrefMaxBitrate;
-  uint32_t mNegotiatedMaxBitrate;
-  uint32_t mMinBitrateEstimate;
+  int mMinBitrate;
+  int mStartBitrate;
+  int mPrefMaxBitrate;
+  int mNegotiatedMaxBitrate;
+  int mMinBitrateEstimate;
 
   bool mRtpStreamIdEnabled;
   uint8_t mRtpStreamIdExtId;
 
   static const unsigned int sAlphaNum = 7;
   static const unsigned int sAlphaDen = 8;
   static const unsigned int sRoundingPadding = 1024;
 
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -745,35 +745,34 @@ MediaPipeline::UpdateTransport_s(int lev
   } else {
     filter_ = filter;
   }
 }
 
 void
 MediaPipeline::SelectSsrc_m(size_t ssrc_index)
 {
-  RUN_ON_THREAD(sts_thread_,
-                WrapRunnable(
-                    this,
-                    &MediaPipeline::SelectSsrc_s,
-                    ssrc_index),
-                NS_DISPATCH_NORMAL);
+  if (ssrc_index < ssrcs_received_.size()) {
+    uint32_t ssrc = ssrcs_received_[ssrc_index];
+    RUN_ON_THREAD(sts_thread_,
+                  WrapRunnable(
+                               this,
+                               &MediaPipeline::SelectSsrc_s,
+                               ssrc),
+                  NS_DISPATCH_NORMAL);
+
+    conduit_->SetRemoteSSRC(ssrc);
+  }
 }
 
 void
-MediaPipeline::SelectSsrc_s(size_t ssrc_index)
+MediaPipeline::SelectSsrc_s(uint32_t ssrc)
 {
   filter_ = new MediaPipelineFilter;
-  if (ssrc_index < ssrcs_received_.size()) {
-    filter_->AddRemoteSSRC(ssrcs_received_[ssrc_index]);
-  } else {
-    MOZ_MTLOG(ML_WARNING, "SelectSsrc called with " << ssrc_index << " but we "
-                          << "have only seen " << ssrcs_received_.size()
-                          << " ssrcs");
-  }
+  filter_->AddRemoteSSRC(ssrc);
 }
 
 void MediaPipeline::StateChange(TransportFlow *flow, TransportLayer::State state) {
   TransportInfo* info = GetTransportInfo_s(flow);
   MOZ_ASSERT(info);
 
   if (state == TransportLayer::TS_OPEN) {
     MOZ_MTLOG(ML_INFO, "Flow is ready");
@@ -2189,26 +2188,24 @@ public:
                         uint32_t y_stride,
                         uint32_t cbcr_stride,
                         uint32_t time_stamp,
                         int64_t render_time,
                         const RefPtr<layers::Image>& video_image)
   {
 #ifdef MOZILLA_INTERNAL_API
     ReentrantMonitorAutoEnter enter(monitor_);
-#endif // MOZILLA_INTERNAL_API
 
-#if defined(MOZILLA_INTERNAL_API)
     if (buffer) {
       // Create a video frame using |buffer|.
 #ifdef MOZ_WIDGET_GONK
       RefPtr<PlanarYCbCrImage> yuvImage = new GrallocImage();
 #else
       RefPtr<PlanarYCbCrImage> yuvImage = image_container_->CreatePlanarYCbCrImage();
-#endif
+#endif // MOZ_WIDGET_GONK
       uint8_t* frame = const_cast<uint8_t*>(static_cast<const uint8_t*> (buffer));
 
       PlanarYCbCrData yuvData;
       yuvData.mYChannel = frame;
       yuvData.mYSize = IntSize(y_stride, height_);
       yuvData.mYStride = y_stride;
       yuvData.mCbCrStride = cbcr_stride;
       yuvData.mCbChannel = frame + height_ * yuvData.mYStride;
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -119,17 +119,17 @@ class MediaPipeline : public sigslot::ha
   void UpdateTransport_s(int level,
                          RefPtr<TransportFlow> rtp_transport,
                          RefPtr<TransportFlow> rtcp_transport,
                          nsAutoPtr<MediaPipelineFilter> filter);
 
   // Used only for testing; installs a MediaPipelineFilter that filters
   // everything but the nth ssrc
   void SelectSsrc_m(size_t ssrc_index);
-  void SelectSsrc_s(size_t ssrc_index);
+  void SelectSsrc_s(uint32_t ssrc);
 
   virtual Direction direction() const { return direction_; }
   virtual const std::string& trackid() const { return track_id_; }
   virtual int level() const { return level_; }
   virtual bool IsVideo() const = 0;
 
   bool IsDoingRtcpMux() const {
     return (rtp_.type_ == MUX);
--- a/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
@@ -152,25 +152,28 @@ NegotiatedDetailsToVideoCodecConfigs(con
 {
   std::vector<JsepCodecDescription*> codecs(GetCodecs(aDetails));
   for (const JsepCodecDescription* codec : codecs) {
     VideoCodecConfig* config;
     if (NS_FAILED(JsepCodecDescToCodecConfig(*codec, &config))) {
       return NS_ERROR_INVALID_ARG;
     }
 
+    config->mTias = aDetails.GetTias();
+
     for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) {
       const JsepTrackEncoding& jsepEncoding(aDetails.GetEncoding(i));
       if (jsepEncoding.HasFormat(codec->mDefaultPt)) {
         VideoCodecConfig::SimulcastEncoding encoding;
         encoding.rid = jsepEncoding.mRid;
         encoding.constraints = jsepEncoding.mConstraints;
         config->mSimulcastEncodings.push_back(encoding);
       }
     }
+
     aConfigs->values.push_back(config);
   }
 
   return NS_OK;
 }
 
 // Accessing the PCMedia should be safe here because we shouldn't
 // have enqueued this function unless it was still active and
--- a/security/sandbox/mac/Sandbox.h
+++ b/security/sandbox/mac/Sandbox.h
@@ -32,33 +32,34 @@ typedef struct _MacSandboxPluginInfo {
       pluginBinaryPath(other.pluginBinaryPath) {}
   MacSandboxPluginType type;
   std::string pluginPath;
   std::string pluginBinaryPath;
 } MacSandboxPluginInfo;
 
 typedef struct _MacSandboxInfo {
   _MacSandboxInfo()
-    : type(MacSandboxType_Default), level(0) {}
+    : type(MacSandboxType_Default), level(0), shouldLog(true) {}
   _MacSandboxInfo(const struct _MacSandboxInfo& other)
     : type(other.type), level(other.level),
       hasSandboxedProfile(other.hasSandboxedProfile),
       pluginInfo(other.pluginInfo),
       appPath(other.appPath), appBinaryPath(other.appBinaryPath),
       appDir(other.appDir), appTempDir(other.appTempDir),
-      profileDir(other.profileDir) {}
+      profileDir(other.profileDir), shouldLog(other.shouldLog) {}
   MacSandboxType type;
   int32_t level;
   bool hasSandboxedProfile;
   MacSandboxPluginInfo pluginInfo;
   std::string appPath;
   std::string appBinaryPath;
   std::string appDir;
   std::string appTempDir;
   std::string profileDir;
+  bool shouldLog;
 } MacSandboxInfo;
 
 namespace mozilla {
 
 bool StartMacSandbox(MacSandboxInfo aInfo, std::string &aErrorMessage);
 
 } // namespace mozilla
 
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -117,17 +117,17 @@ OSXVersion::GetVersionNumber()
   }
   return mOSXVersion;
 }
 
 namespace mozilla {
 
 static const char pluginSandboxRules[] =
   "(version 1)\n"
-  "(deny default)\n"
+  "(deny default %s)\n"
   "(allow signal (target self))\n"
   "(allow sysctl-read)\n"
   "(allow iokit-open (iokit-user-client-class \"IOHIDParamUserClient\"))\n"
   "(allow mach-lookup\n"
   "    (global-name \"com.apple.cfprefsd.agent\")\n"
   "    (global-name \"com.apple.cfprefsd.daemon\")\n"
   "    (global-name \"com.apple.system.opendirectoryd.libinfo\")\n"
   "    (global-name \"com.apple.system.logger\")\n"
@@ -190,17 +190,17 @@ static const char contentSandboxRules[] 
   "  file-write-data\n"
   "  file-ioctl\n"
   "  (literal \"/dev/dtracehelper\"))\n"
   "\n"
   "; Used to read hw.ncpu, hw.physicalcpu_max, kern.ostype, and others\n"
   "(allow sysctl-read)\n"
   "\n"
   "(begin\n"
-  "  (deny default)\n"
+  "  (deny default %s)\n"
   "  (debug deny)\n"
   "\n"
   "  (define resolving-literal literal)\n"
   "  (define resolving-subpath subpath)\n"
   "  (define resolving-regex regex)\n"
   "\n"
   "  (define container-path appPath)\n"
   "  (define appdir-path appDir)\n"
@@ -401,21 +401,24 @@ static const char contentSandboxRules[] 
   "  (allow network-outbound (literal \"/private/var/run/cupsd\"))\n"
 #ifdef DEBUG
   "\n"
   "; bug 1303987\n"
   "  (allow file-write* (var-folders-regex \"/\"))\n"
 #endif
   ")\n";
 
+static const char* NO_LOGGING_CMD = "(with no-log)";
+
 bool StartMacSandbox(MacSandboxInfo aInfo, std::string &aErrorMessage)
 {
   char *profile = NULL;
   if (aInfo.type == MacSandboxType_Plugin) {
     asprintf(&profile, pluginSandboxRules,
+             aInfo.shouldLog ? "" : NO_LOGGING_CMD,
              aInfo.pluginInfo.pluginBinaryPath.c_str(),
              aInfo.appPath.c_str(),
              aInfo.appBinaryPath.c_str());
 
     if (profile &&
       aInfo.pluginInfo.type == MacSandboxPluginType_GMPlugin_EME_Widevine) {
       char *widevineProfile = NULL;
       asprintf(&widevineProfile, "%s%s", profile,
@@ -430,17 +433,18 @@ bool StartMacSandbox(MacSandboxInfo aInf
       asprintf(&profile, contentSandboxRules, aInfo.level,
                OSXVersion::OSXVersionMinor(),
                aInfo.appPath.c_str(),
                aInfo.appBinaryPath.c_str(),
                aInfo.appDir.c_str(),
                aInfo.appTempDir.c_str(),
                aInfo.hasSandboxedProfile ? 1 : 0,
                aInfo.profileDir.c_str(),
-               getenv("HOME"));
+               getenv("HOME"),
+               aInfo.shouldLog ? "" : NO_LOGGING_CMD);
     } else {
       fprintf(stderr,
         "Content sandbox disabled due to sandbox level setting\n");
       return false;
     }
   }
   else {
     char *msg = NULL;
--- a/taskcluster/scripts/misc/build-clang-tidy-macosx.sh
+++ b/taskcluster/scripts/misc/build-clang-tidy-macosx.sh
@@ -12,17 +12,16 @@ cd $HOME_DIR/src
 TOOLTOOL_MANIFEST=browser/config/tooltool-manifests/macosx64/cross-clang.manifest
 . taskcluster/scripts/misc/tooltool-download.sh
 
 # ld needs libLTO.so from llvm
 export LD_LIBRARY_PATH=$HOME_DIR/src/clang/lib
 # these variables are used in build-clang.py
 export CROSS_CCTOOLS_PATH=$HOME_DIR/src/cctools
 export CROSS_SYSROOT=$HOME_DIR/src/MacOSX10.10.sdk
-export LIBCXX_INCLUDE_PATH=$HOME_DIR/src/clang/include/c++/v1
 # cmake doesn't allow us to specify a path to lipo on the command line.
 ln -sf $CROSS_CCTOOLS_PATH/bin/x86_64-apple-darwin10-lipo /usr/bin/lipo
 
 # gets a bit too verbose here
 set +x
 
 cd build/build-clang
 # |mach python| sets up a virtualenv for us!
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -104,17 +104,17 @@ function testInit() {
   }
   if (gConfig.e10s) {
     e10s_init();
 
     let processCount = prefs.getIntPref("dom.ipc.processCount", 1);
     if (processCount > 1) {
       // Currently starting a content process is slow, to aviod timeouts, let's
       // keep alive content processes.
-      prefs.setIntPref("dom.ipc.keepProcessesAlive", processCount);
+      prefs.setIntPref("dom.ipc.keepProcessesAlive.web", processCount);
     }
 
     let globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
                      .getService(Ci.nsIMessageListenerManager);
     globalMM.loadFrameScript("chrome://mochikit/content/shutdown-leaks-collector.js", true);
   } else {
     // In non-e10s, only run the ShutdownLeaksCollector in the parent process.
     Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm");
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -2240,17 +2240,16 @@ toolbar#nav-bar {
             # 1325148, but it couldn't land until all the regressions were also fixed or
             # backed out. Rather than waiting and risking new regressions, in the meantime
             # this code will selectively disable leak checking on flavors/directories where
             # known regressions exist. At least this way we can prevent further damage while
             # they get fixed.
 
             info = mozinfo.info
             skip_leak_conditions = [
-                (info['debug'] and options.flavor == 'plain' and d.startswith('toolkit/components/extensions/test/mochitest') and info['os'] == 'mac', 'bug 1326456'),  # noqa
                 (info['debug'] and options.flavor == 'plain' and d == 'toolkit/components/prompts/test' and info['os'] == 'mac', 'bug 1325275'),  # noqa
             ]
 
             for condition, reason in skip_leak_conditions:
                 if condition:
                     self.log.warning('WARNING | disabling leakcheck due to {}'.format(reason))
                     self.disable_leak_checking = True
                     break
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -23,17 +23,17 @@ const Cr = Components.results;
 
 Cu.importGlobalProperties(["TextEncoder"]);
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 /* globals processCount */
 
-XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount");
+XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount.extension");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionAPIs",
                                   "resource://gre/modules/ExtensionAPI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage",
@@ -625,16 +625,18 @@ this.Extension = class extends Extension
     this.addonData = addonData;
     this.startupReason = startupReason;
 
     this.remote = ExtensionManagement.useRemoteWebExtensions;
 
     if (this.remote && processCount !== 1) {
       throw new Error("Out-of-process WebExtensions are not supported with multiple child processes");
     }
+    // This is filled in the first time an extension child is created.
+    this.parentMessageManager = null;
 
     this.id = addonData.id;
     this.baseURI = NetUtil.newURI(this.getURL("")).QueryInterface(Ci.nsIURL);
     this.principal = this.createPrincipal();
 
     this.onStartup = null;
 
     this.hasShutdown = false;
@@ -644,27 +646,16 @@ this.Extension = class extends Extension
 
     this.apis = [];
     this.whiteListedHosts = null;
     this.webAccessibleResources = null;
 
     this.emitter = new EventEmitter();
   }
 
-  get parentMessageManager() {
-    if (this.remote) {
-      // We currently run extensions in the normal web content process. Since
-      // we currently only support remote extensions in single-child e10s,
-      // child 0 is always the current process, and child 1 is always the
-      // remote extension process.
-      return Services.ppmm.getChildAt(1);
-    }
-    return Services.ppmm.getChildAt(0);
-  }
-
   static set browserUpdated(updated) {
     _browserUpdated = updated;
   }
 
   static get browserUpdated() {
     return _browserUpdated;
   }
 
@@ -951,17 +942,17 @@ this.Extension = class extends Extension
     MessageChannel.abortResponses({extensionId: this.id});
 
     ExtensionManagement.shutdownExtension(this.uuid);
 
     this.cleanupGeneratedFile();
   }
 
   observe(subject, topic, data) {
-    if (topic == "xpcom-shutdown") {
+    if (topic === "xpcom-shutdown") {
       this.cleanupGeneratedFile();
     }
   }
 
   hasPermission(perm) {
     let match = /^manifest:(.*)/.exec(perm);
     if (match) {
       return this.manifest[match[1]] != null;
--- a/toolkit/components/extensions/ExtensionManagement.jsm
+++ b/toolkit/components/extensions/ExtensionManagement.jsm
@@ -10,16 +10,18 @@ const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils",
                                   "resource://gre/modules/ExtensionUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "console", () => ExtensionUtils.getConsole());
 
 XPCOMUtils.defineLazyGetter(this, "UUIDMap", () => {
   let {UUIDMap} = Cu.import("resource://gre/modules/Extension.jsm", {});
   return UUIDMap;
@@ -300,18 +302,20 @@ function getAPILevelForWindow(window, ad
   }
 
   // WebExtension URLs loaded into top frames UI could have full API level privileges.
   return FULL_PRIVILEGES;
 }
 
 ExtensionManagement = {
   get isExtensionProcess() {
-    return (this.useRemoteWebExtensions ||
-            Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT);
+    if (this.useRemoteWebExtensions) {
+      return Services.appinfo.remoteType === E10SUtils.EXTENSION_REMOTE_TYPE;
+    }
+    return Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
   },
 
   startupExtension: Service.startupExtension.bind(Service),
   shutdownExtension: Service.shutdownExtension.bind(Service),
 
   registerAPI: APIs.register.bind(APIs),
   unregisterAPI: APIs.unregister.bind(APIs),
 
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -17,16 +17,18 @@ this.EXPORTED_SYMBOLS = ["ExtensionParen
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
                                   "resource://gre/modules/MessageChannel.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
                                   "resource://gre/modules/NativeMessaging.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
@@ -387,65 +389,90 @@ ParentAPIManager = {
   observe(subject, topic, data) {
     if (topic === "message-manager-close") {
       let mm = subject;
       for (let [childId, context] of this.proxyContexts) {
         if (context.parentMessageManager === mm) {
           this.closeProxyContext(childId);
         }
       }
+
+      // Reset extension message managers when their child processes shut down.
+      for (let extension of GlobalManager.extensionMap.values()) {
+        if (extension.parentMessageManager === mm) {
+          extension.parentMessageManager = null;
+        }
+      }
     }
   },
 
   shutdownExtension(extensionId) {
     for (let [childId, context] of this.proxyContexts) {
       if (context.extension.id == extensionId) {
         context.shutdown();
         this.proxyContexts.delete(childId);
       }
     }
   },
 
   receiveMessage({name, data, target}) {
-    switch (name) {
-      case "API:CreateProxyContext":
-        this.createProxyContext(data, target);
-        break;
+    try {
+      switch (name) {
+        case "API:CreateProxyContext":
+          this.createProxyContext(data, target);
+          break;
 
-      case "API:CloseProxyContext":
-        this.closeProxyContext(data.childId);
-        break;
+        case "API:CloseProxyContext":
+          this.closeProxyContext(data.childId);
+          break;
 
-      case "API:Call":
-        this.call(data, target);
-        break;
+        case "API:Call":
+          this.call(data, target);
+          break;
 
-      case "API:AddListener":
-        this.addListener(data, target);
-        break;
+        case "API:AddListener":
+          this.addListener(data, target);
+          break;
 
-      case "API:RemoveListener":
-        this.removeListener(data);
-        break;
+        case "API:RemoveListener":
+          this.removeListener(data);
+          break;
+      }
+    } catch (e) {
+      Cu.reportError(e);
     }
   },
 
   createProxyContext(data, target) {
     let {envType, extensionId, childId, principal} = data;
     if (this.proxyContexts.has(childId)) {
       throw new Error("A WebExtension context with the given ID already exists!");
     }
 
     let extension = GlobalManager.getExtension(extensionId);
     if (!extension) {
       throw new Error(`No WebExtension found with ID ${extensionId}`);
     }
 
     let context;
     if (envType == "addon_parent" || envType == "devtools_parent") {
+      let processMessageManager = (target.messageManager.processMessageManager ||
+                                   Services.ppmm.getChildAt(0));
+
+      if (!extension.parentMessageManager) {
+        let expectedRemoteType = extension.remote ? E10SUtils.EXTENSION_REMOTE_TYPE : null;
+        if (target.remoteType === expectedRemoteType) {
+          extension.parentMessageManager = processMessageManager;
+        }
+      }
+
+      if (processMessageManager !== extension.parentMessageManager) {
+        throw new Error("Attempt to create privileged extension parent from incorrect child process");
+      }
+
       context = new ExtensionPageContextParent(envType, extension, data, target);
     } else if (envType == "content_parent") {
       context = new ContentScriptContextParent(envType, extension, data, target, principal);
     } else {
       throw new Error(`Invalid WebExtension context envType: ${envType}`);
     }
     this.proxyContexts.set(childId, context);
   },
--- a/toolkit/components/extensions/ext-backgroundPage.js
+++ b/toolkit/components/extensions/ext-backgroundPage.js
@@ -2,16 +2,18 @@
 
 var {interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 const {
   promiseDocumentLoaded,
   promiseEvent,
   promiseObserved,
@@ -52,16 +54,17 @@ class BackgroundPageBase {
       let browser = chromeDoc.createElement("browser");
       browser.setAttribute("type", "content");
       browser.setAttribute("disableglobalhistory", "true");
       browser.setAttribute("webextension-view-type", "background");
 
       let awaitFrameLoader;
       if (this.extension.remote) {
         browser.setAttribute("remote", "true");
+        browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
         awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
       }
 
       chromeDoc.documentElement.appendChild(browser);
       yield awaitFrameLoader;
 
       this.browser = browser;
 
--- a/toolkit/components/extensions/test/mochitest/head.js
+++ b/toolkit/components/extensions/test/mochitest/head.js
@@ -1,19 +1,22 @@
 "use strict";
 
 // We run tests under two different configurations, from mochitest.ini and
 // mochitest-remote.ini. When running from mochitest-remote.ini, the tests are
 // copied to the sub-directory "test-oop-extensions", which we detect here, and
 // use to select our configuration.
 if (location.pathname.includes("test-oop-extensions")) {
   SpecialPowers.pushPrefEnv({set: [
-    ["dom.ipc.processCount", 1],
+    ["dom.ipc.processCount.extension", 1],
     ["extensions.webextensions.remote", true],
   ]});
+  // We don't want to reset this at the end of the test, so that we don't have
+  // to spawn a new extension child process for each test unit.
+  SpecialPowers.setIntPref("dom.ipc.keepProcessesAlive.extension", 1);
 }
 
 /* exported waitForLoad */
 
 function waitForLoad(win) {
   return new Promise(resolve => {
     win.addEventListener("load", function listener() {
       win.removeEventListener("load", listener, true);
--- a/toolkit/components/telemetry/TelemetryScalar.cpp
+++ b/toolkit/components/telemetry/TelemetryScalar.cpp
@@ -78,17 +78,21 @@ const uint32_t kMaximumKeyStringLength =
 const uint32_t kMaximumStringValueLength = 50;
 const uint32_t kScalarCount =
   static_cast<uint32_t>(mozilla::Telemetry::ScalarID::ScalarCount);
 
 enum class ScalarResult : uint8_t {
   // Nothing went wrong.
   Ok,
   // General Scalar Errors
+  NotInitialized,
+  CannotUnpackVariant,
   CannotRecordInProcess,
+  KeyedTypeMismatch,
+  UnknownScalar,
   OperationNotSupported,
   InvalidType,
   InvalidValue,
   // Keyed Scalar Errors
   KeyTooLong,
   TooManyKeys,
   // String Scalar Errors
   StringTooLong,
@@ -97,48 +101,16 @@ enum class ScalarResult : uint8_t {
   UnsignedTruncatedValue
 };
 
 typedef nsBaseHashtableET<nsDepCharHashKey, mozilla::Telemetry::ScalarID>
           CharPtrEntryType;
 
 typedef AutoHashtable<CharPtrEntryType> ScalarMapType;
 
-/**
- * Map the error codes used internally to NS_* error codes.
- * @param aSr The error code used internally in this module.
- * @return {nsresult} A NS_* error code.
- */
-nsresult
-MapToNsResult(ScalarResult aSr)
-{
-  switch (aSr) {
-    case ScalarResult::Ok:
-    case ScalarResult::CannotRecordInProcess:
-      return NS_OK;
-    case ScalarResult::OperationNotSupported:
-      return NS_ERROR_NOT_AVAILABLE;
-    case ScalarResult::StringTooLong:
-      // We don't want to throw if we're setting a string that is too long.
-      return NS_OK;
-    case ScalarResult::InvalidType:
-    case ScalarResult::InvalidValue:
-    case ScalarResult::KeyTooLong:
-      return NS_ERROR_ILLEGAL_VALUE;
-    case ScalarResult::TooManyKeys:
-      return NS_ERROR_FAILURE;
-    case ScalarResult::UnsignedNegativeValue:
-    case ScalarResult::UnsignedTruncatedValue:
-      // We shouldn't throw if trying to set a negative number or are truncated,
-      // only warn the user.
-      return NS_OK;
-  }
-  return NS_ERROR_FAILURE;
-}
-
 bool
 IsValidEnumId(mozilla::Telemetry::ScalarID aID)
 {
   return aID < mozilla::Telemetry::ScalarID::ScalarCount;
 }
 
 /**
  * The following helpers are used to get a nsIVariant from a uint32_t,
@@ -778,59 +750,53 @@ ProcessesKeyedScalarsMapType gKeyedScala
 // back into the TelemetryScalar interface, hence trying to re-acquire the mutex.
 //
 // This means that these functions potentially race against threads, but
 // that seems preferable to risking deadlock.
 
 namespace {
 
 /**
- * Checks if the error should be logged.
- *
- * @param aSr The error code.
- * @return true if the error should be logged, false otherwise.
- */
-bool
-internal_ShouldLogError(ScalarResult aSr)
-{
-  switch (aSr) {
-    case ScalarResult::CannotRecordInProcess: MOZ_FALLTHROUGH;
-    case ScalarResult::StringTooLong: MOZ_FALLTHROUGH;
-    case ScalarResult::KeyTooLong: MOZ_FALLTHROUGH;
-    case ScalarResult::TooManyKeys: MOZ_FALLTHROUGH;
-    case ScalarResult::UnsignedNegativeValue: MOZ_FALLTHROUGH;
-    case ScalarResult::UnsignedTruncatedValue:
-      // Intentional fall-through.
-      return true;
-
-    default:
-      return false;
-  }
-
-  // It should never reach this point.
-  return false;
-}
-
-/**
  * Converts the error code to a human readable error message and prints it to the
  * browser console.
  *
  * @param aScalarName The name of the scalar that raised the error.
  * @param aSr The error code.
  */
 void
 internal_LogScalarError(const nsACString& aScalarName, ScalarResult aSr)
 {
   nsAutoString errorMessage;
   AppendUTF8toUTF16(aScalarName, errorMessage);
 
   switch (aSr) {
+    case ScalarResult::NotInitialized:
+      errorMessage.Append(NS_LITERAL_STRING(" - Telemetry was not yet initialized."));
+      break;
+    case ScalarResult::CannotUnpackVariant:
+      errorMessage.Append(NS_LITERAL_STRING(" - Cannot convert the provided JS value to nsIVariant."));
+      break;
     case ScalarResult::CannotRecordInProcess:
       errorMessage.Append(NS_LITERAL_STRING(" - Cannot record the scalar in the current process."));
       break;
+    case ScalarResult::KeyedTypeMismatch:
+      errorMessage.Append(NS_LITERAL_STRING(" - Attempting to manage a keyed scalar as a scalar (or vice-versa)."));
+      break;
+    case ScalarResult::UnknownScalar:
+      errorMessage.Append(NS_LITERAL_STRING(" - Unknown scalar."));
+      break;
+    case ScalarResult::OperationNotSupported:
+      errorMessage.Append(NS_LITERAL_STRING(" - The requested operation is not supported on this scalar."));
+      break;
+    case ScalarResult::InvalidType:
+      errorMessage.Append(NS_LITERAL_STRING(" - Attempted to set the scalar to an invalid data type."));
+      break;
+    case ScalarResult::InvalidValue:
+      errorMessage.Append(NS_LITERAL_STRING(" - Attempted to set the scalar to an incompatible value."));
+      break;
     case ScalarResult::StringTooLong:
       errorMessage.Append(NS_LITERAL_STRING(" - Truncating scalar value to 50 characters."));
       break;
     case ScalarResult::KeyTooLong:
       errorMessage.Append(NS_LITERAL_STRING(" - The key length must be limited to 70 characters."));
       break;
     case ScalarResult::TooManyKeys:
       errorMessage.Append(NS_LITERAL_STRING(" - Keyed scalars cannot have more than 100 keys."));
@@ -1044,16 +1010,77 @@ internal_GetRecordableScalar(mozilla::Te
   // Are we allowed to record this scalar?
   if (!internal_CanRecordForScalarID(aId) || !internal_CanRecordProcess(aId)) {
     return nullptr;
   }
 
   return scalar;
 }
 
+/**
+ * Update the scalar with the provided value. This is used by the JS API.
+ *
+ * @param aName The scalar name.
+ * @param aType The action type for updating the scalar.
+ * @param aValue The value to use for updating the scalar.
+ * @return a ScalarResult error value.
+ */
+ScalarResult
+internal_UpdateScalar(const nsACString& aName, ScalarActionType aType,
+                      nsIVariant* aValue)
+{
+  mozilla::Telemetry::ScalarID id;
+  nsresult rv = internal_GetEnumByScalarName(aName, &id);
+  if (NS_FAILED(rv)) {
+    return (rv == NS_ERROR_FAILURE) ?
+           ScalarResult::NotInitialized : ScalarResult::UnknownScalar;
+  }
+
+  // We're trying to set a plain scalar, so make sure this is one.
+  if (internal_IsKeyedScalar(id)) {
+    return ScalarResult::KeyedTypeMismatch;
+  }
+
+  // Are we allowed to record this scalar?
+  if (!internal_CanRecordForScalarID(id)) {
+    return ScalarResult::Ok;
+  }
+
+  // Can we record in this process?
+  if (!internal_CanRecordProcess(id)) {
+    return ScalarResult::CannotRecordInProcess;
+  }
+
+  // Accumulate in the child process if needed.
+  if (!XRE_IsParentProcess()) {
+    const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
+    TelemetryIPCAccumulator::RecordChildScalarAction(id, info.kind, aType, aValue);
+    return ScalarResult::Ok;
+  }
+
+  // Finally get the scalar.
+  ScalarBase* scalar = nullptr;
+  rv = internal_GetScalarByEnum(id, GeckoProcessType_Default, &scalar);
+  if (NS_FAILED(rv)) {
+    // Don't throw on expired scalars.
+    if (rv == NS_ERROR_NOT_AVAILABLE) {
+      return ScalarResult::Ok;
+    }
+    return ScalarResult::UnknownScalar;
+  }
+
+  if (aType == ScalarActionType::eAdd) {
+    return scalar->AddValue(aValue);
+  } else if (aType == ScalarActionType::eSet) {
+    return scalar->SetValue(aValue);
+  }
+
+  return scalar->SetMaximum(aValue);
+}
+
 } // namespace
 
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // PRIVATE: thread-unsafe helpers for the keyed scalars
@@ -1152,16 +1179,78 @@ internal_GetRecordableKeyedScalar(mozill
   // Are we allowed to record this scalar?
   if (!internal_CanRecordForScalarID(aId) || !internal_CanRecordProcess(aId)) {
     return nullptr;
   }
 
   return scalar;
 }
 
+/**
+ * Update the keyed scalar with the provided value. This is used by the JS API.
+ *
+ * @param aName The scalar name.
+ * @param aKey The key name.
+ * @param aType The action type for updating the scalar.
+ * @param aValue The value to use for updating the scalar.
+ * @return a ScalarResult error value.
+ */
+ScalarResult
+internal_UpdateKeyedScalar(const nsACString& aName, const nsAString& aKey,
+                           ScalarActionType aType, nsIVariant* aValue)
+{
+  mozilla::Telemetry::ScalarID id;
+  nsresult rv = internal_GetEnumByScalarName(aName, &id);
+  if (NS_FAILED(rv)) {
+    return (rv == NS_ERROR_FAILURE) ?
+           ScalarResult::NotInitialized : ScalarResult::UnknownScalar;
+  }
+
+  // We're trying to set a keyed scalar, so make sure this is one.
+  if (!internal_IsKeyedScalar(id)) {
+    return ScalarResult::KeyedTypeMismatch;
+  }
+
+  // Are we allowed to record this scalar?
+  if (!internal_CanRecordForScalarID(id)) {
+    return ScalarResult::Ok;
+  }
+
+  // Can we record in this process?
+  if (!internal_CanRecordProcess(id)) {
+    return ScalarResult::CannotRecordInProcess;
+  }
+
+  // Accumulate in the child process if needed.
+  if (!XRE_IsParentProcess()) {
+    const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
+    TelemetryIPCAccumulator::RecordChildKeyedScalarAction(id, aKey, info.kind, aType, aValue);
+    return ScalarResult::Ok;
+  }
+
+  // Finally get the scalar.
+  KeyedScalar* scalar = nullptr;
+  rv = internal_GetKeyedScalarByEnum(id, GeckoProcessType_Default, &scalar);
+  if (NS_FAILED(rv)) {
+    // Don't throw on expired scalars.
+    if (rv == NS_ERROR_NOT_AVAILABLE) {
+      return ScalarResult::Ok;
+    }
+    return ScalarResult::UnknownScalar;
+  }
+
+  if (aType == ScalarActionType::eAdd) {
+    return scalar->AddValue(aKey, aValue);
+  } else if (aType == ScalarActionType::eSet) {
+    return scalar->SetValue(aKey, aValue);
+  }
+
+  return scalar->SetMaximum(aKey, aValue);
+}
+
 } // namespace
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // EXTERNALLY VISIBLE FUNCTIONS in namespace TelemetryScalars::
 
 // This is a StaticMutex rather than a plain Mutex (1) so that
@@ -1226,158 +1315,80 @@ TelemetryScalar::SetCanRecordExtended(bo
 }
 
 /**
  * Adds the value to the given scalar.
  *
  * @param aName The scalar name.
  * @param aVal The numeric value to add to the scalar.
  * @param aCx The JS context.
- * @return NS_OK if the value was added or if we're not allowed to record to this
- *  dataset. Otherwise, return an error.
+ * @return NS_OK (always) so that the JS API call doesn't throw. In case of errors,
+ *         a warning level message is printed in the browser console.
  */
 nsresult
 TelemetryScalar::Add(const nsACString& aName, JS::HandleValue aVal, JSContext* aCx)
 {
   // Unpack the aVal to nsIVariant. This uses the JS context.
   nsCOMPtr<nsIVariant> unpackedVal;
   nsresult rv =
     nsContentUtils::XPConnect()->JSToVariant(aCx, aVal,  getter_AddRefs(unpackedVal));
   if (NS_FAILED(rv)) {
-    return rv;
+    internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
+    return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-
-    mozilla::Telemetry::ScalarID id;
-    rv = internal_GetEnumByScalarName(aName, &id);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // We're trying to set a plain scalar, so make sure this is one.
-    if (internal_IsKeyedScalar(id)) {
-      return NS_ERROR_ILLEGAL_VALUE;
-    }
-
-    // Are we allowed to record this scalar?
-    if (!internal_CanRecordForScalarID(id)) {
-      return NS_OK;
-    }
-
-    if (internal_CanRecordProcess(id)) {
-      // Accumulate in the child process if needed.
-      if (!XRE_IsParentProcess()) {
-        const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
-        TelemetryIPCAccumulator::RecordChildScalarAction(id, info.kind, ScalarActionType::eAdd,
-                                                         unpackedVal);
-        return NS_OK;
-      }
-
-      // Finally get the scalar.
-      ScalarBase* scalar = nullptr;
-      rv = internal_GetScalarByEnum(id, GeckoProcessType_Default, &scalar);
-      if (NS_FAILED(rv)) {
-        // Don't throw on expired scalars.
-        if (rv == NS_ERROR_NOT_AVAILABLE) {
-          return NS_OK;
-        }
-        return rv;
-      }
-
-      sr = scalar->AddValue(unpackedVal);
-    } else {
-      sr = ScalarResult::CannotRecordInProcess;
-    }
+    sr = internal_UpdateScalar(aName, ScalarActionType::eAdd, unpackedVal);
   }
 
   // Warn the user about the error if we need to.
-  if (internal_ShouldLogError(sr)) {
+  if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
-  return MapToNsResult(sr);
+  return NS_OK;
 }
 
 /**
  * Adds the value to the given scalar.
  *
  * @param aName The scalar name.
  * @param aKey The key name.
  * @param aVal The numeric value to add to the scalar.
  * @param aCx The JS context.
- * @return NS_OK if the value was added or if we're not allow to record to this
- *  dataset. Otherwise, return an error.
+ * @return NS_OK (always) so that the JS API call doesn't throw. In case of errors,
+ *         a warning level message is printed in the browser console.
  */
 nsresult
 TelemetryScalar::Add(const nsACString& aName, const nsAString& aKey, JS::HandleValue aVal,
                      JSContext* aCx)
 {
   // Unpack the aVal to nsIVariant. This uses the JS context.
   nsCOMPtr<nsIVariant> unpackedVal;
   nsresult rv =
     nsContentUtils::XPConnect()->JSToVariant(aCx, aVal,  getter_AddRefs(unpackedVal));
   if (NS_FAILED(rv)) {
-    return rv;
+    internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
+    return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-
-    mozilla::Telemetry::ScalarID id;
-    rv = internal_GetEnumByScalarName(aName, &id);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // Make sure this is a keyed scalar.
-    if (!internal_IsKeyedScalar(id)) {
-      return NS_ERROR_ILLEGAL_VALUE;
-    }
-
-    // Are we allowed to record this scalar?
-    if (!internal_CanRecordForScalarID(id)) {
-      return NS_OK;
-    }
-
-    if (internal_CanRecordProcess(id)) {
-      // Accumulate in the child process if needed.
-      if (!XRE_IsParentProcess()) {
-        const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
-        TelemetryIPCAccumulator::RecordChildKeyedScalarAction(
-          id, aKey, info.kind, ScalarActionType::eAdd, unpackedVal);
-        return NS_OK;
-      }
-
-      // Finally get the scalar.
-      KeyedScalar* scalar = nullptr;
-      rv = internal_GetKeyedScalarByEnum(id, GeckoProcessType_Default, &scalar);
-      if (NS_FAILED(rv)) {
-        // Don't throw on expired scalars.
-        if (rv == NS_ERROR_NOT_AVAILABLE) {
-          return NS_OK;
-        }
-        return rv;
-      }
-
-      sr = scalar->AddValue(aKey, unpackedVal);
-    } else {
-      sr = ScalarResult::CannotRecordInProcess;
-    }
+    sr = internal_UpdateKeyedScalar(aName, aKey, ScalarActionType::eAdd, unpackedVal);
   }
 
   // Warn the user about the error if we need to.
-  if (internal_ShouldLogError(sr)) {
+  if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
-  return MapToNsResult(sr);
+  return NS_OK;
 }
 
 /**
  * Adds the value to the given scalar.
  *
  * @param aId The scalar enum id.
  * @param aVal The numeric value to add to the scalar.
  */
@@ -1442,158 +1453,80 @@ TelemetryScalar::Add(mozilla::Telemetry:
 }
 
 /**
  * Sets the scalar to the given value.
  *
  * @param aName The scalar name.
  * @param aVal The value to set the scalar to.
  * @param aCx The JS context.
- * @return NS_OK if the value was added or if we're not allow to record to this
- *  dataset. Otherwise, return an error.
+ * @return NS_OK (always) so that the JS API call doesn't throw. In case of errors,
+ *         a warning level message is printed in the browser console.
  */
 nsresult
 TelemetryScalar::Set(const nsACString& aName, JS::HandleValue aVal, JSContext* aCx)
 {
   // Unpack the aVal to nsIVariant. This uses the JS context.
   nsCOMPtr<nsIVariant> unpackedVal;
   nsresult rv =
     nsContentUtils::XPConnect()->JSToVariant(aCx, aVal,  getter_AddRefs(unpackedVal));
   if (NS_FAILED(rv)) {
-    return rv;
+    internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
+    return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-
-    mozilla::Telemetry::ScalarID id;
-    rv = internal_GetEnumByScalarName(aName, &id);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // We're trying to set a plain scalar, so make sure this is one.
-    if (internal_IsKeyedScalar(id)) {
-      return NS_ERROR_ILLEGAL_VALUE;
-    }
-
-    // Are we allowed to record this scalar?
-    if (!internal_CanRecordForScalarID(id)) {
-      return NS_OK;
-    }
-
-    if (internal_CanRecordProcess(id)) {
-      // Accumulate in the child process if needed.
-      if (!XRE_IsParentProcess()) {
-        const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
-        TelemetryIPCAccumulator::RecordChildScalarAction(id, info.kind, ScalarActionType::eSet,
-                                                         unpackedVal);
-        return NS_OK;
-      }
-
-      // Finally get the scalar.
-      ScalarBase* scalar = nullptr;
-      rv = internal_GetScalarByEnum(id, GeckoProcessType_Default, &scalar);
-      if (NS_FAILED(rv)) {
-        // Don't throw on expired scalars.
-        if (rv == NS_ERROR_NOT_AVAILABLE) {
-          return NS_OK;
-        }
-        return rv;
-      }
-
-      sr = scalar->SetValue(unpackedVal);
-    } else {
-      sr = ScalarResult::CannotRecordInProcess;
-    }
+    sr = internal_UpdateScalar(aName, ScalarActionType::eSet, unpackedVal);
   }
 
   // Warn the user about the error if we need to.
-  if (internal_ShouldLogError(sr)) {
+  if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
-  return MapToNsResult(sr);
+  return NS_OK;
 }
 
 /**
  * Sets the keyed scalar to the given value.
  *
  * @param aName The scalar name.
  * @param aKey The key name.
  * @param aVal The value to set the scalar to.
  * @param aCx The JS context.
- * @return NS_OK if the value was added or if we're not allow to record to this
- *  dataset. Otherwise, return an error.
+ * @return NS_OK (always) so that the JS API call doesn't throw. In case of errors,
+ *         a warning level message is printed in the browser console.
  */
 nsresult
 TelemetryScalar::Set(const nsACString& aName, const nsAString& aKey, JS::HandleValue aVal,
                      JSContext* aCx)
 {
   // Unpack the aVal to nsIVariant. This uses the JS context.
   nsCOMPtr<nsIVariant> unpackedVal;
   nsresult rv =
     nsContentUtils::XPConnect()->JSToVariant(aCx, aVal,  getter_AddRefs(unpackedVal));
   if (NS_FAILED(rv)) {
-    return rv;
+    internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
+    return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-
-    mozilla::Telemetry::ScalarID id;
-    rv = internal_GetEnumByScalarName(aName, &id);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // We're trying to set a keyed scalar. Report an error if this isn't one.
-    if (!internal_IsKeyedScalar(id)) {
-      return NS_ERROR_ILLEGAL_VALUE;
-    }
-
-    // Are we allowed to record this scalar?
-    if (!internal_CanRecordForScalarID(id)) {
-      return NS_OK;
-    }
-
-    if (internal_CanRecordProcess(id)) {
-      // Accumulate in the child process if needed.
-      if (!XRE_IsParentProcess()) {
-        const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
-        TelemetryIPCAccumulator::RecordChildKeyedScalarAction(
-          id, aKey, info.kind, ScalarActionType::eSet, unpackedVal);
-        return NS_OK;
-      }
-
-      // Finally get the scalar.
-      KeyedScalar* scalar = nullptr;
-      rv = internal_GetKeyedScalarByEnum(id, GeckoProcessType_Default, &scalar);
-      if (NS_FAILED(rv)) {
-        // Don't throw on expired scalars.
-        if (rv == NS_ERROR_NOT_AVAILABLE) {
-          return NS_OK;
-        }
-        return rv;
-      }
-
-      sr = scalar->SetValue(aKey, unpackedVal);
-    } else {
-      sr = ScalarResult::CannotRecordInProcess;
-    }
+    sr = internal_UpdateKeyedScalar(aName, aKey, ScalarActionType::eSet, unpackedVal);
   }
 
   // Warn the user about the error if we need to.
-  if (internal_ShouldLogError(sr)) {
+  if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
-  return MapToNsResult(sr);
+  return NS_OK;
 }
 
 /**
  * Sets the scalar to the given numeric value.
  *
  * @param aId The scalar enum id.
  * @param aValue The numeric, unsigned value to set the scalar to.
  */
@@ -1756,158 +1689,80 @@ TelemetryScalar::Set(mozilla::Telemetry:
 }
 
 /**
  * Sets the scalar to the maximum of the current and the passed value.
  *
  * @param aName The scalar name.
  * @param aVal The numeric value to set the scalar to.
  * @param aCx The JS context.
- * @return NS_OK if the value was added or if we're not allow to record to this
- *  dataset. Otherwise, return an error.
+ * @return NS_OK (always) so that the JS API call doesn't throw. In case of errors,
+ *         a warning level message is printed in the browser console.
  */
 nsresult
 TelemetryScalar::SetMaximum(const nsACString& aName, JS::HandleValue aVal, JSContext* aCx)
 {
   // Unpack the aVal to nsIVariant. This uses the JS context.
   nsCOMPtr<nsIVariant> unpackedVal;
   nsresult rv =
     nsContentUtils::XPConnect()->JSToVariant(aCx, aVal,  getter_AddRefs(unpackedVal));
   if (NS_FAILED(rv)) {
-    return rv;
+    internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
+    return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-
-    mozilla::Telemetry::ScalarID id;
-    rv = internal_GetEnumByScalarName(aName, &id);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // Make sure this is not a keyed scalar.
-    if (internal_IsKeyedScalar(id)) {
-      return NS_ERROR_ILLEGAL_VALUE;
-    }
-
-    // Are we allowed to record this scalar?
-    if (!internal_CanRecordForScalarID(id)) {
-      return NS_OK;
-    }
-
-    if (internal_CanRecordProcess(id)) {
-      // Accumulate in the child process if needed.
-      if (!XRE_IsParentProcess()) {
-        const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
-        TelemetryIPCAccumulator::RecordChildScalarAction(id, info.kind, ScalarActionType::eSetMaximum,
-                                                         unpackedVal);
-        return NS_OK;
-      }
-
-      // Finally get the scalar.
-      ScalarBase* scalar = nullptr;
-      rv = internal_GetScalarByEnum(id, GeckoProcessType_Default, &scalar);
-      if (NS_FAILED(rv)) {
-        // Don't throw on expired scalars.
-        if (rv == NS_ERROR_NOT_AVAILABLE) {
-          return NS_OK;
-        }
-        return rv;
-      }
-
-      sr = scalar->SetMaximum(unpackedVal);
-    } else {
-      sr = ScalarResult::CannotRecordInProcess;
-    }
+    sr = internal_UpdateScalar(aName, ScalarActionType::eSetMaximum, unpackedVal);
   }
 
   // Warn the user about the error if we need to.
-  if (internal_ShouldLogError(sr)) {
+  if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
-  return MapToNsResult(sr);
+  return NS_OK;
 }
 
 /**
  * Sets the scalar to the maximum of the current and the passed value.
  *
  * @param aName The scalar name.
  * @param aKey The key name.
  * @param aVal The numeric value to set the scalar to.
  * @param aCx The JS context.
- * @return NS_OK if the value was added or if we're not allow to record to this
- *  dataset. Otherwise, return an error.
+ * @return NS_OK (always) so that the JS API call doesn't throw. In case of errors,
+ *         a warning level message is printed in the browser console.
  */
 nsresult
 TelemetryScalar::SetMaximum(const nsACString& aName, const nsAString& aKey, JS::HandleValue aVal,
                             JSContext* aCx)
 {
   // Unpack the aVal to nsIVariant. This uses the JS context.
   nsCOMPtr<nsIVariant> unpackedVal;
   nsresult rv =
     nsContentUtils::XPConnect()->JSToVariant(aCx, aVal,  getter_AddRefs(unpackedVal));
   if (NS_FAILED(rv)) {
-    return rv;
+    internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
+    return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-
-    mozilla::Telemetry::ScalarID id;
-    rv = internal_GetEnumByScalarName(aName, &id);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    // Make sure this is a keyed scalar.
-    if (!internal_IsKeyedScalar(id)) {
-      return NS_ERROR_ILLEGAL_VALUE;
-    }
-
-    // Are we allowed to record this scalar?
-    if (!internal_CanRecordForScalarID(id)) {
-      return NS_OK;
-    }
-
-    if (internal_CanRecordProcess(id)) {
-      // Accumulate in the child process if needed.
-      if (!XRE_IsParentProcess()) {
-        const ScalarInfo &info = gScalars[static_cast<uint32_t>(id)];
-        TelemetryIPCAccumulator::RecordChildKeyedScalarAction(
-          id, aKey, info.kind, ScalarActionType::eSetMaximum, unpackedVal);
-        return NS_OK;
-      }
-
-      // Finally get the scalar.
-      KeyedScalar* scalar = nullptr;
-      rv = internal_GetKeyedScalarByEnum(id, GeckoProcessType_Default, &scalar);
-      if (NS_FAILED(rv)) {
-        // Don't throw on expired scalars.
-        if (rv == NS_ERROR_NOT_AVAILABLE) {
-          return NS_OK;
-        }
-        return rv;
-      }
-
-      sr = scalar->SetMaximum(aKey, unpackedVal);
-    } else {
-      sr = ScalarResult::CannotRecordInProcess;
-    }
+    sr = internal_UpdateKeyedScalar(aName, aKey, ScalarActionType::eSetMaximum, unpackedVal);
   }
 
   // Warn the user about the error if we need to.
-  if (internal_ShouldLogError(sr)) {
+  if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
-  return MapToNsResult(sr);
+  return NS_OK;
 }
 
 /**
  * Sets the scalar to the maximum of the current and the passed value.
  *
  * @param aId The scalar enum id.
  * @param aValue The numeric value to set the scalar to.
  */
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js
@@ -82,37 +82,26 @@ add_task(function* test_keyedSerializati
                KEYED_UINT_SCALAR + "." + expectedOtherKey + " must have the correct value.");
 });
 
 add_task(function* test_nonexistingScalar() {
   const NON_EXISTING_SCALAR = "telemetry.test.non_existing";
 
   Telemetry.clearScalars();
 
-  // Make sure we throw on any operation for non-existing scalars.
-  Assert.throws(() => Telemetry.scalarAdd(NON_EXISTING_SCALAR, 11715),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Adding to a non existing scalar must throw.");
-  Assert.throws(() => Telemetry.scalarSet(NON_EXISTING_SCALAR, 11715),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Setting a non existing scalar must throw.");
-  Assert.throws(() => Telemetry.scalarSetMaximum(NON_EXISTING_SCALAR, 11715),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Setting the maximum of a non existing scalar must throw.");
+  // The JS API must not throw when used incorrectly but rather print
+  // a message to the console.
+  Telemetry.scalarAdd(NON_EXISTING_SCALAR, 11715);
+  Telemetry.scalarSet(NON_EXISTING_SCALAR, 11715);
+  Telemetry.scalarSetMaximum(NON_EXISTING_SCALAR, 11715);
 
-  // Make sure we throw on any operation for non-existing scalars.
-  Assert.throws(() => Telemetry.keyedScalarAdd(NON_EXISTING_SCALAR, "some_key", 11715),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Adding to a non existing keyed scalar must throw.");
-  Assert.throws(() => Telemetry.keyedScalarSet(NON_EXISTING_SCALAR, "some_key", 11715),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Setting a non existing keyed scalar must throw.");
-  Assert.throws(() => Telemetry.keyedScalarSetMaximum(NON_EXISTING_SCALAR, "some_key", 11715),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Setting the maximum of a non keyed existing scalar must throw.");
+  // Make sure we do not throw on any operation for non-existing scalars.
+  Telemetry.keyedScalarAdd(NON_EXISTING_SCALAR, "some_key", 11715);
+  Telemetry.keyedScalarSet(NON_EXISTING_SCALAR, "some_key", 11715);
+  Telemetry.keyedScalarSetMaximum(NON_EXISTING_SCALAR, "some_key", 11715);
 
   // Get a snapshot of the scalars.
   const scalars = getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
 
   Assert.ok(!(NON_EXISTING_SCALAR in scalars), "The non existing scalar must not be persisted.");
 
   const keyedScalars =
     getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
@@ -192,27 +181,22 @@ add_task(function* test_unsignedIntScala
 
   // Setting or adding a negative number must report an error through
   // the console and drop the change (shouldn't throw).
   Telemetry.scalarAdd(UINT_SCALAR, -5);
   Telemetry.scalarSet(UINT_SCALAR, -5);
   Telemetry.scalarSetMaximum(UINT_SCALAR, -1);
   checkScalar(3);
 
-  // What happens if we try to set a value of a different type?
+  // If we try to set a value of a different type, the JS API should not
+  // throw but rather print a console message.
   Telemetry.scalarSet(UINT_SCALAR, 1);
-  Assert.throws(() => Telemetry.scalarSet(UINT_SCALAR, "unexpected value"),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Setting the scalar to an unexpected value type must throw.");
-  Assert.throws(() => Telemetry.scalarAdd(UINT_SCALAR, "unexpected value"),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Adding an unexpected value type must throw.");
-  Assert.throws(() => Telemetry.scalarSetMaximum(UINT_SCALAR, "unexpected value"),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Setting the scalar to an unexpected value type must throw.");
+  Telemetry.scalarSet(UINT_SCALAR, "unexpected value");
+  Telemetry.scalarAdd(UINT_SCALAR, "unexpected value");
+  Telemetry.scalarSetMaximum(UINT_SCALAR, "unexpected value");
   // The stored value must not be compromised.
   checkScalar(1);
 });
 
 add_task(function* test_stringScalar() {
   let checkExpectedString = (expectedString) => {
     const scalars =
       getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
@@ -226,31 +210,21 @@ add_task(function* test_stringScalar() {
   let expected = "test string";
   Telemetry.scalarSet(STRING_SCALAR, expected);
   checkExpectedString(expected);
   expected = "漢語";
   Telemetry.scalarSet(STRING_SCALAR, expected);
   checkExpectedString(expected);
 
   // We have some unsupported operations for strings.
-  Assert.throws(() => Telemetry.scalarAdd(STRING_SCALAR, 1),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarAdd(STRING_SCALAR, "string value"),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarSetMaximum(STRING_SCALAR, 1),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarSetMaximum(STRING_SCALAR, "string value"),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarSet(STRING_SCALAR, 1),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "The string scalar must throw if we're not setting a string.");
+  Telemetry.scalarAdd(STRING_SCALAR, 1);
+  Telemetry.scalarAdd(STRING_SCALAR, "string value");
+  Telemetry.scalarSetMaximum(STRING_SCALAR, 1);
+  Telemetry.scalarSetMaximum(STRING_SCALAR, "string value");
+  Telemetry.scalarSet(STRING_SCALAR, 1);
 
   // Try to set the scalar to a string longer than the maximum length limit.
   const LONG_STRING = "browser.qaxfiuosnzmhlg.rpvxicawolhtvmbkpnludhedobxvkjwqyeyvmv";
   Telemetry.scalarSet(STRING_SCALAR, LONG_STRING);
   checkExpectedString(LONG_STRING.substr(0, 50));
 });
 
 add_task(function* test_booleanScalar() {
@@ -276,32 +250,22 @@ add_task(function* test_booleanScalar() 
   checkExpectedBool(true);
   Telemetry.scalarSet(BOOLEAN_SCALAR, 0);
   checkExpectedBool(false);
   Telemetry.scalarSet(BOOLEAN_SCALAR, 1.0);
   checkExpectedBool(true);
   Telemetry.scalarSet(BOOLEAN_SCALAR, 0.0);
   checkExpectedBool(false);
 
-  // Check that unsupported operations for booleans throw.
-  Assert.throws(() => Telemetry.scalarAdd(BOOLEAN_SCALAR, 1),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarAdd(BOOLEAN_SCALAR, "string value"),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, 1),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, "string value"),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
-  Assert.throws(() => Telemetry.scalarSet(BOOLEAN_SCALAR, "true"),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "The boolean scalar must throw if we're not setting a boolean.");
+  // Check that unsupported operations for booleans do not throw.
+  Telemetry.scalarAdd(BOOLEAN_SCALAR, 1);
+  Telemetry.scalarAdd(BOOLEAN_SCALAR, "string value");
+  Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, 1);
+  Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, "string value");
+  Telemetry.scalarSet(BOOLEAN_SCALAR, "true");
 });
 
 add_task(function* test_scalarRecording() {
   const OPTIN_SCALAR = "telemetry.test.release_optin";
   const OPTOUT_SCALAR = "telemetry.test.release_optout";
 
   let checkValue = (scalarName, expectedValue) => {
     const scalars =
@@ -446,22 +410,20 @@ add_task(function* test_keyed_uint() {
     getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
 
   for (let k = 0; k < 3; k++) {
     const keyName = KEYS[k];
     Assert.equal(keyedScalars[KEYED_UINT_SCALAR][keyName], expectedValues[k],
                  KEYED_UINT_SCALAR + "." + keyName + " must contain the correct value.");
   }
 
-  // Are we still throwing when doing unsupported things on uint keyed scalars?
+  // Do not throw when doing unsupported things on uint keyed scalars.
   // Just test one single unsupported operation, the other are covered in the plain
   // unsigned scalar test.
-  Assert.throws(() => Telemetry.scalarSet(KEYED_UINT_SCALAR, "new_key", "unexpected value"),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Setting the scalar to an unexpected value type must throw.");
+  Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, "new_key", "unexpected value");
 });
 
 add_task(function* test_keyed_boolean() {
   Telemetry.clearScalars();
 
   const KEYED_BOOLEAN_TYPE = "telemetry.test.keyed_boolean_kind";
   const first_key = "first_key";
   const second_key = "second_key";
@@ -485,44 +447,36 @@ add_task(function* test_keyed_boolean() 
 
   keyedScalars =
     getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
   Assert.equal(keyedScalars[KEYED_BOOLEAN_TYPE][first_key], false,
                "The key must contain the expected value.");
   Assert.equal(keyedScalars[KEYED_BOOLEAN_TYPE][second_key], true,
                "The key must contain the expected value.");
 
-  // Are we still throwing when doing unsupported things on a boolean keyed scalars?
+  // Do not throw when doing unsupported things on a boolean keyed scalars.
   // Just test one single unsupported operation, the other are covered in the plain
   // boolean scalar test.
-  Assert.throws(() => Telemetry.keyedScalarAdd(KEYED_BOOLEAN_TYPE, "somehey", 1),
-                /NS_ERROR_NOT_AVAILABLE/,
-                "Using an unsupported operation must throw.");
+  Telemetry.keyedScalarAdd(KEYED_BOOLEAN_TYPE, "somehey", 1);
 });
 
 add_task(function* test_keyed_keys_length() {
   Telemetry.clearScalars();
 
   const LONG_KEY_STRING =
     "browser.qaxfiuosnzmhlg.rpvxicawolhtvmbkpnludhedobxvkjwqyeyvmv.somemoresowereach70chars";
   const NORMAL_KEY = "a_key";
 
   // Set the value for a key within the length limits.
   Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, NORMAL_KEY, 1);
 
-  // Now try to set and modify the value for a very long key.
-  Assert.throws(() => Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Using keys longer than 70 characters must throw.");
-  Assert.throws(() => Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LONG_KEY_STRING, 1),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Using keys longer than 70 characters must throw.");
-  Assert.throws(() => Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10),
-                /NS_ERROR_ILLEGAL_VALUE/,
-                "Using keys longer than 70 characters must throw.");
+  // Now try to set and modify the value for a very long key (must not throw).
+  Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10);
+  Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LONG_KEY_STRING, 1);
+  Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10);
 
   // Make sure the key with the right length contains the expected value.
   let keyedScalars =
     getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
   Assert.equal(Object.keys(keyedScalars[KEYED_UINT_SCALAR]).length, 1,
                "The keyed scalar must contain exactly 1 key.");
   Assert.ok(NORMAL_KEY in keyedScalars[KEYED_UINT_SCALAR],
             "The keyed scalar must contain the expected key.");
@@ -545,25 +499,19 @@ add_task(function* test_keyed_max_keys()
   let valueToSet = 0;
   keyNamesSet.forEach(keyName => {
     Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, keyName, valueToSet++);
   });
 
   // Perform some operations on the 101th key. This should throw, as
   // we're not allowed to have more than 100 keys.
   const LAST_KEY_NAME = "overflowing_key";
-  Assert.throws(() => Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10),
-                /NS_ERROR_FAILURE/,
-                "Using more than 100 keys must throw.");
-  Assert.throws(() => Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LAST_KEY_NAME, 1),
-                /NS_ERROR_FAILURE/,
-                "Using more than 100 keys must throw.");
-  Assert.throws(() => Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10),
-                /NS_ERROR_FAILURE/,
-                "Using more than 100 keys must throw.");
+  Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10);
+  Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LAST_KEY_NAME, 1);
+  Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10);
 
   // Make sure all the keys except the last one are available and have the correct
   // values.
   let keyedScalars =
     getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
 
   // Check that the keyed scalar only contain the first 100 keys.
   const reportedKeysSet = new Set(Object.keys(keyedScalars[KEYED_UINT_SCALAR]));
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -3527,16 +3527,17 @@ var gDetailView = {
     browser.setAttribute("class", "inline-options-browser");
 
     let {optionsURL} = this._addon;
     let remote = !E10SUtils.canLoadURIInProcess(optionsURL, Services.appinfo.PROCESS_TYPE_DEFAULT);
 
     let readyPromise;
     if (remote) {
       browser.setAttribute("remote", "true");
+      browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
       readyPromise = promiseEvent("XULFrameLoaderCreated", browser);
     } else {
       readyPromise = promiseEvent("load", browser, true);
     }
 
     parentNode.appendChild(browser);
 
     // Force bindings to apply synchronously.
--- a/tools/profiler/core/GeckoSampler.cpp
+++ b/tools/profiler/core/GeckoSampler.cpp
@@ -4,61 +4,55 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <algorithm>
 #include <string>
 #include <stdio.h>
 #include <fstream>
 #include <sstream>
 #include "GeckoProfiler.h"
-#ifndef SPS_STANDALONE
 #include "SaveProfileTask.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 #include "prtime.h"
 #include "nsXULAppAPI.h"
-#endif
 #include "ProfileEntry.h"
 #include "SyncProfile.h"
 #include "platform.h"
 #include "shared-libraries.h"
 #include "mozilla/StackWalk.h"
 #include "GeckoSampler.h"
 
 // JSON
 #include "ProfileJSONWriter.h"
 
-#ifndef SPS_STANDALONE
 // Meta
 #include "nsXPCOM.h"
 #include "nsXPCOMCID.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIXULRuntime.h"
 #include "nsIXULAppInfo.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "PlatformMacros.h"
 #include "nsTArray.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/ProfileGatherer.h"
-#endif
 
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   #include "FennecJNIWrappers.h"
 #endif
 
-#ifndef SPS_STANDALONE
 // JS
 #include "jsfriendapi.h"
 #include "js/ProfilingFrameIterator.h"
-#endif
 
 #if defined(MOZ_PROFILING) && (defined(XP_MACOSX) || defined(XP_WIN))
  #define USE_NS_STACKWALK
 #endif
 
 #if defined(XP_WIN)
 typedef CONTEXT tickcontext_t;
 #elif defined(LINUX)
@@ -69,23 +63,21 @@ typedef ucontext_t tickcontext_t;
 #if defined(__arm__) && defined(ANDROID)
  // Should also work on ARM Linux, but not tested there yet.
  #define USE_EHABI_STACKWALK
 #endif
 #ifdef USE_EHABI_STACKWALK
  #include "EHABIStackWalk.h"
 #endif
 
-#ifndef SPS_STANDALONE
 #if defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_x86_linux)
 # define USE_LUL_STACKWALK
 # include "lul/LulMain.h"
 # include "lul/platform-linux-lul.h"
 #endif
-#endif
 
 using std::string;
 using namespace mozilla;
 
 #ifndef MAXPATHLEN
  #ifdef PATH_MAX
   #define MAXPATHLEN PATH_MAX
  #elif defined(MAX_PATH)
@@ -175,44 +167,33 @@ hasFeature(const char** aFeatures, uint3
 }
 
 GeckoSampler::GeckoSampler(double aInterval, int aEntrySize,
                          const char** aFeatures, uint32_t aFeatureCount,
                          const char** aThreadNameFilters, uint32_t aFilterCount)
   : Sampler(aInterval, true, aEntrySize)
   , mBuffer(new ProfileBuffer(aEntrySize))
   , mSaveRequested(false)
-#if defined(XP_WIN)
-  , mIntelPowerGadget(nullptr)
-#endif
 {
   mUseStackWalk = hasFeature(aFeatures, aFeatureCount, "stackwalk");
 
   mProfileJS = hasFeature(aFeatures, aFeatureCount, "js");
   mProfileGPU = hasFeature(aFeatures, aFeatureCount, "gpu");
-  mProfilePower = hasFeature(aFeatures, aFeatureCount, "power");
   // Users sometimes ask to filter by a list of threads but forget to request
   // profiling non main threads. Let's make it implificit if we have a filter
   mProfileThreads = hasFeature(aFeatures, aFeatureCount, "threads") || aFilterCount > 0;
   mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf");
   mPrivacyMode = hasFeature(aFeatures, aFeatureCount, "privacy");
   mAddMainThreadIO = hasFeature(aFeatures, aFeatureCount, "mainthreadio");
   mProfileMemory = hasFeature(aFeatures, aFeatureCount, "memory");
   mTaskTracer = hasFeature(aFeatures, aFeatureCount, "tasktracer");
   mLayersDump = hasFeature(aFeatures, aFeatureCount, "layersdump");
   mDisplayListDump = hasFeature(aFeatures, aFeatureCount, "displaylistdump");
   mProfileRestyle = hasFeature(aFeatures, aFeatureCount, "restyle");
 
-#if defined(XP_WIN)
-  if (mProfilePower) {
-    mIntelPowerGadget = new IntelPowerGadget();
-    mProfilePower = mIntelPowerGadget->Init();
-  }
-#endif
-
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   mProfileJava = mozilla::jni::IsFennec() &&
       hasFeature(aFeatures, aFeatureCount, "java");
 #else
   mProfileJava = false;
 #endif
 
   // Deep copy aThreadNameFilters
@@ -269,19 +250,16 @@ GeckoSampler::~GeckoSampler()
       // information for an old thread.
       if (info->IsPendingDelete()) {
         delete info;
         sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
         i--;
       }
     }
   }
-#if defined(XP_WIN)
-  delete mIntelPowerGadget;
-#endif
 
   // Cancel any in-flight async profile gatherering
   // requests
   mGatherer->Cancel();
 
 #ifdef MOZ_TASK_TRACER
   if (mTaskTracer) {
     mozilla::tasktracer::StopLogging();
@@ -290,22 +268,20 @@ GeckoSampler::~GeckoSampler()
 }
 
 void GeckoSampler::HandleSaveRequest()
 {
   if (!mSaveRequested)
     return;
   mSaveRequested = false;
 
-#ifndef SPS_STANDALONE
   // TODO: Use use the ipc/chromium Tasks here to support processes
   // without XPCOM.
   nsCOMPtr<nsIRunnable> runnable = new SaveProfileTask();
   NS_DispatchToMainThread(runnable);
-#endif
 }
 
 void GeckoSampler::DeleteExpiredMarkers()
 {
   mBuffer->deleteExpiredStoredMarkers();
 }
 
 void GeckoSampler::StreamTaskTracer(SpliceableJSONWriter& aWriter)
@@ -347,17 +323,16 @@ void GeckoSampler::StreamMetaJSCustomObj
   aWriter.IntProperty("stackwalk", mUseStackWalk);
 
 #ifdef DEBUG
   aWriter.IntProperty("debug", 1);
 #else
   aWriter.IntProperty("debug", 0);
 #endif
 
-#ifndef SPS_STANDALONE
   aWriter.IntProperty("gcpoison", JS::IsGCPoisoning() ? 1 : 0);
 
   bool asyncStacks = Preferences::GetBool("javascript.options.asyncstack");
   aWriter.IntProperty("asyncstack", asyncStacks);
 
   mozilla::TimeDuration delta = mozilla::TimeStamp::Now() - sStartTime;
   aWriter.DoubleProperty("startTime", static_cast<double>(PR_Now()/1000.0 - delta.ToMilliseconds()));
 
@@ -397,26 +372,24 @@ void GeckoSampler::StreamMetaJSCustomObj
   nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
   if (appInfo) {
     nsAutoCString string;
 
     res = appInfo->GetName(string);
     if (!NS_FAILED(res))
       aWriter.StringProperty("product", string.Data());
   }
-#endif
 }
 
 void GeckoSampler::ToStreamAsJSON(std::ostream& stream, double aSinceTime)
 {
   SpliceableJSONWriter b(mozilla::MakeUnique<OStreamJSONWriteFunc>(stream));
   StreamJSON(b, aSinceTime);
 }
 
-#ifndef SPS_STANDALONE
 JSObject* GeckoSampler::ToJSObject(JSContext *aCx, double aSinceTime)
 {
   JS::RootedValue val(aCx);
   {
     UniquePtr<char[]> buf = ToJSON(aSinceTime);
     NS_ConvertUTF8toUTF16 js_string(nsDependentCString(buf.get()));
     MOZ_ALWAYS_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(js_string.get()),
                                  js_string.Length(), &val));
@@ -426,17 +399,16 @@ JSObject* GeckoSampler::ToJSObject(JSCon
 
 void GeckoSampler::GetGatherer(nsISupports** aRetVal)
 {
   if (!aRetVal || NS_WARN_IF(!mGatherer)) {
     return;
   }
   NS_ADDREF(*aRetVal = mGatherer);
 }
-#endif
 
 UniquePtr<char[]> GeckoSampler::ToJSON(double aSinceTime)
 {
   SpliceableChunkedJSONWriter b;
   StreamJSON(b, aSinceTime);
   return b.WriteFunc()->CopyData();
 }
 
@@ -566,17 +538,16 @@ void GeckoSampler::StreamJSON(Spliceable
           // have been marked for pending delete.
 
           ::MutexAutoLock lock(sRegisteredThreads->at(i)->Profile()->GetMutex());
 
           sRegisteredThreads->at(i)->Profile()->StreamJSON(aWriter, aSinceTime);
         }
       }
 
-#ifndef SPS_STANDALONE
       if (Sampler::CanNotifyObservers()) {
         // Send a event asking any subprocesses (plugins) to
         // give us their information
         SubprocessClosure closure(&aWriter);
         nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
         if (os) {
           RefPtr<ProfileSaveEvent> pse = new ProfileSaveEvent(SubProcessCallback, &closure);
           os->NotifyObservers(pse, "profiler-subprocess", nullptr);
@@ -591,28 +562,26 @@ void GeckoSampler::StreamJSON(Spliceable
         {
           BuildJavaThreadJSObject(aWriter);
         }
         aWriter.End();
 
         java::GeckoJavaSampler::Unpause();
       }
   #endif
-#endif
 
       SetPaused(false);
     }
     aWriter.EndArray();
   }
   aWriter.End();
 }
 
 void GeckoSampler::FlushOnJSShutdown(JSContext* aContext)
 {
-#ifndef SPS_STANDALONE
   SetPaused(true);
 
   {
     ::MutexAutoLock lock(*sRegisteredThreadsMutex);
 
     for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
       // Thread not being profiled, skip it.
       if (!sRegisteredThreads->at(i)->Profile() ||
@@ -626,28 +595,25 @@ void GeckoSampler::FlushOnJSShutdown(JSC
       }
 
       ::MutexAutoLock lock(sRegisteredThreads->at(i)->Profile()->GetMutex());
       sRegisteredThreads->at(i)->Profile()->FlushSamplesAndMarkers();
     }
   }
 
   SetPaused(false);
-#endif
 }
 
 void PseudoStack::flushSamplerOnJSShutdown()
 {
-#ifndef SPS_STANDALONE
   MOZ_ASSERT(mContext);
   GeckoSampler* t = tlsTicker.get();
   if (t) {
     t->FlushOnJSShutdown(mContext);
   }
-#endif
 }
 
 // END SaveProfileTask et al
 ////////////////////////////////////////////////////////////////////////
 
 static
 void addDynamicTag(ThreadProfile &aProfile, char aTagName, const char *aStr)
 {
@@ -682,17 +648,16 @@ void addPseudoEntry(volatile StackEntry 
   // First entry has tagName 's' (start)
   // Check for magic pointer bit 1 to indicate copy
   const char* sampleLabel = entry.label();
   if (entry.isCopyLabel()) {
     // Store the string using 1 or more 'd' (dynamic) tags
     // that will happen to the preceding tag
 
     addDynamicTag(aProfile, 'c', sampleLabel);
-#ifndef SPS_STANDALONE
     if (entry.isJs()) {
       JSScript* script = entry.script();
       if (script) {
         if (!entry.pc()) {
           // The JIT only allows the top-most entry to have a nullptr pc
           MOZ_ASSERT(&entry == &stack->mStack[stack->stackSize() - 1]);
           // If stack-walking was disabled, then that's just unfortunate
           if (lastpc) {
@@ -704,17 +669,16 @@ void addPseudoEntry(volatile StackEntry 
           }
         } else {
           lineno = JS_PCToLineNumber(script, entry.pc());
         }
       }
     } else {
       lineno = entry.line();
     }
-#endif
   } else {
     aProfile.addTag(ProfileEntry('c', sampleLabel));
 
     // XXX: Bug 1010578. Don't assume a CPP entry and try to get the
     // line for js entries as well.
     if (entry.isCpp()) {
       lineno = entry.line();
     }
@@ -773,17 +737,16 @@ void mergeStacksIntoProfile(ThreadProfil
   // entries.
   uint32_t startBufferGen;
   if (aSample->isSamplingCurrentThread) {
     startBufferGen = UINT32_MAX;
   } else {
     startBufferGen = aProfile.bufferGeneration();
   }
   uint32_t jsCount = 0;
-#ifndef SPS_STANDALONE
   JS::ProfilingFrameIterator::Frame jsFrames[1000];
   // Only walk jit stack if profiling frame iterator is turned on.
   if (pseudoStack->mContext && JS::IsProfilingEnabledForContext(pseudoStack->mContext)) {
     AutoWalkJSStack autoWalkJSStack;
     const uint32_t maxFrames = mozilla::ArrayLength(jsFrames);
 
     if (aSample && autoWalkJSStack.walkAllowed) {
       JS::ProfilingFrameIterator::RegisterState registerState;
@@ -807,17 +770,16 @@ void mergeStacksIntoProfile(ThreadProfil
           mozilla::Maybe<JS::ProfilingFrameIterator::Frame> frame =
             jsIter.getPhysicalFrameWithoutLabel();
           if (frame.isSome())
             jsFrames[jsCount++] = frame.value();
         }
       }
     }
   }
-#endif
 
   // Start the sample with a root entry.
   aProfile.addTag(ProfileEntry('s', "(root)"));
 
   // While the pseudo-stack array is ordered oldest-to-youngest, the JS and
   // native arrays are ordered youngest-to-oldest. We must add frames to
   // aProfile oldest-to-youngest. Thus, iterate over the pseudo-stack forwards
   // and JS and native arrays backwards. Note: this means the terminating
@@ -837,38 +799,34 @@ void mergeStacksIntoProfile(ThreadProfil
     uint8_t *nativeStackAddr = nullptr;
 
     if (pseudoIndex != pseudoCount) {
       volatile StackEntry &pseudoFrame = pseudoFrames[pseudoIndex];
 
       if (pseudoFrame.isCpp())
         lastPseudoCppStackAddr = (uint8_t *) pseudoFrame.stackAddress();
 
-#ifndef SPS_STANDALONE
       // Skip any pseudo-stack JS frames which are marked isOSR
       // Pseudostack frames are marked isOSR when the JS interpreter
       // enters a jit frame on a loop edge (via on-stack-replacement,
       // or OSR).  To avoid both the pseudoframe and jit frame being
       // recorded (and showing up twice), the interpreter marks the
       // interpreter pseudostack entry with the OSR flag to ensure that
       // it doesn't get counted.
       if (pseudoFrame.isJs() && pseudoFrame.isOSR()) {
           pseudoIndex++;
           continue;
       }
-#endif
 
       MOZ_ASSERT(lastPseudoCppStackAddr);
       pseudoStackAddr = lastPseudoCppStackAddr;
     }
 
-#ifndef SPS_STANDALONE
     if (jsIndex >= 0)
       jsStackAddr = (uint8_t *) jsFrames[jsIndex].stackAddress;
-#endif
 
     if (nativeIndex >= 0)
       nativeStackAddr = (uint8_t *) aNativeStack.sp_array[nativeIndex];
 
     // If there's a native stack entry which has the same SP as a
     // pseudo stack entry, pretend we didn't see the native stack
     // entry.  Ditto for a native stack entry which has the same SP as
     // a JS stack entry.  In effect this means pseudo or JS entries
@@ -891,17 +849,16 @@ void mergeStacksIntoProfile(ThreadProfil
     if (pseudoStackAddr > jsStackAddr && pseudoStackAddr > nativeStackAddr) {
       MOZ_ASSERT(pseudoIndex < pseudoCount);
       volatile StackEntry &pseudoFrame = pseudoFrames[pseudoIndex];
       addPseudoEntry(pseudoFrame, aProfile, pseudoStack, nullptr);
       pseudoIndex++;
       continue;
     }
 
-#ifndef SPS_STANDALONE
     // Check to see if JS jit stack frame is top-most
     if (jsStackAddr > nativeStackAddr) {
       MOZ_ASSERT(jsIndex >= 0);
       const JS::ProfilingFrameIterator::Frame& jsFrame = jsFrames[jsIndex];
 
       // Stringifying non-wasm JIT frames is delayed until streaming
       // time. To re-lookup the entry in the JitcodeGlobalTable, we need to
       // store the JIT code address ('J') in the circular buffer.
@@ -922,43 +879,40 @@ void mergeStacksIntoProfile(ThreadProfil
         MOZ_ASSERT(jsFrame.kind == JS::ProfilingFrameIterator::Frame_Ion ||
                    jsFrame.kind == JS::ProfilingFrameIterator::Frame_Baseline);
         aProfile.addTag(ProfileEntry('J', jsFrames[jsIndex].returnAddress));
       }
 
       jsIndex--;
       continue;
     }
-#endif
 
     // If we reach here, there must be a native stack entry and it must be the
     // greatest entry.
     if (nativeStackAddr) {
       MOZ_ASSERT(nativeIndex >= 0);
       aProfile
         .addTag(ProfileEntry('l', (void*)aNativeStack.pc_array[nativeIndex]));
     }
     if (nativeIndex >= 0) {
       nativeIndex--;
     }
   }
 
-#ifndef SPS_STANDALONE
   // Update the JS context with the current profile sample buffer generation.
   //
   // Do not do this for synchronous sampling, which create their own
   // ProfileBuffers.
   if (!aSample->isSamplingCurrentThread && pseudoStack->mContext) {
     MOZ_ASSERT(aProfile.bufferGeneration() >= startBufferGen);
     uint32_t lapCount = aProfile.bufferGeneration() - startBufferGen;
     JS::UpdateJSContextProfilerSampleBufferGen(pseudoStack->mContext,
                                                aProfile.bufferGeneration(),
                                                lapCount);
   }
-#endif
 }
 
 #ifdef USE_NS_STACKWALK
 static