Merge inbound to mozilla-central. a=merge
authorTiberius Oros <toros@mozilla.com>
Thu, 09 Aug 2018 13:02:05 +0300
changeset 430750 f650c0df72f9f1dc616bb1510a36f894400e8b84
parent 430594 eb9ff7de69efb6486f86656c6fe4b013b27910e4 (current diff)
parent 430749 21cbd16b3b271dcea0a2899629191f84e5ad4278 (diff)
child 430773 7579b609d28e8555062738cbeb5105507a9db968
child 430819 f8f0cd99d049cc695050c21068137d544c8cdf3a
push id34410
push usertoros@mozilla.com
push dateThu, 09 Aug 2018 10:02:47 +0000
treeherdermozilla-central@f650c0df72f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
f650c0df72f9 / 63.0a1 / 20180809101613 / files
nightly linux64
f650c0df72f9 / 63.0a1 / 20180809101613 / files
nightly mac
f650c0df72f9 / 63.0a1 / 20180809101613 / files
nightly win32
f650c0df72f9 / 63.0a1 / 20180809101613 / files
nightly win64
f650c0df72f9 / 63.0a1 / 20180809101613 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
.inferconfig
browser/components/extensions/test/browser/browser-common.ini
devtools/shared/css/generated/properties-db.js
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/html/HTMLImageElement.cpp
dom/html/HTMLImageElement.h
dom/indexedDB/test/test_wasm_cursors.html
dom/indexedDB/test/test_wasm_getAll.html
dom/indexedDB/test/test_wasm_index_getAllObjects.html
dom/indexedDB/test/test_wasm_indexes.html
dom/indexedDB/test/test_wasm_serialize_tiering.html
dom/indexedDB/test/unit/test_wasm_cursors.js
dom/indexedDB/test/unit/test_wasm_getAll.js
dom/indexedDB/test/unit/test_wasm_index_getAllObjects.js
dom/indexedDB/test/unit/test_wasm_indexes.js
dom/indexedDB/test/unit/test_wasm_serialize_tiering.js
dom/svg/SVGImageElement.cpp
dom/svg/SVGImageElement.h
dom/xul/XULDocument.cpp
dom/xul/XULDocument.h
testing/web-platform/meta/encoding/idlharness.any.js.ini
testing/web-platform/meta/encoding/textdecoder-ignorebom.any.js.ini
testing/web-platform/meta/payment-handler/interfaces.https.any.js.ini
testing/web-platform/mozilla/tests/wasm/indexeddb.js.html
testing/web-platform/mozilla/tests/wasm/js/indexeddb.js
testing/web-platform/tests/IndexedDB/wasm-module-value.html
testing/web-platform/tests/css/css-contain/contain-paint-003.html
testing/web-platform/tests/css/css-contain/contain-style-counters.html
testing/web-platform/tests/css/css-pseudo/interfaces.html
testing/web-platform/tests/hr-time/idlharness.html
testing/web-platform/tests/html-media-capture/idlharness.html
testing/web-platform/tests/interfaces/touchevents.idl
testing/web-platform/tests/interfaces/webrtc-pc.idl
testing/web-platform/tests/notifications/interfaces.html
testing/web-platform/tests/payment-handler/interfaces.https.any.js
testing/web-platform/tests/push-api/idlharness.https.any.js
testing/web-platform/tests/uievents/auxclick/auxclick_event-manual.html
testing/web-platform/tests/url/url-tojson.html
testing/web-platform/tests/url/urlencoded-parser.html
testing/web-platform/tests/url/urlsearchparams-append.html
testing/web-platform/tests/url/urlsearchparams-constructor.html
testing/web-platform/tests/url/urlsearchparams-delete.html
testing/web-platform/tests/url/urlsearchparams-foreach.html
testing/web-platform/tests/url/urlsearchparams-get.html
testing/web-platform/tests/url/urlsearchparams-getall.html
testing/web-platform/tests/url/urlsearchparams-has.html
testing/web-platform/tests/url/urlsearchparams-set.html
testing/web-platform/tests/url/urlsearchparams-sort.html
testing/web-platform/tests/url/urlsearchparams-stringifier.html
testing/web-platform/tests/wasm/wasm_idb_worker.js
testing/web-platform/tests/wasm/wasm_indexeddb_test.https.html
testing/web-platform/tests/wasm/wasm_indexeddb_test.js
testing/web-platform/tests/webrtc/interfaces.https.html
testing/web-platform/tests/webxr/interfaces.https.html
deleted file mode 100644
--- a/.inferconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "infer-blacklist-path-regex": [
-        // This is full of issues, and is a dependency we need to discard
-        // sooner rather than later anyway:
-        "mobile/android/thirdparty/ch/boye/httpclientandroidlib"
-    ]
-}
\ No newline at end of file
--- a/accessible/interfaces/ia2/moz.build
+++ b/accessible/interfaces/ia2/moz.build
@@ -93,11 +93,8 @@ RCINCLUDE = 'IA2Marshal.rc'
 # Suppress warnings from the MIDL generated code.
 if CONFIG['CC_TYPE'] == 'clang-cl':
     CFLAGS += [
         '-Wno-extern-initializer',
         '-Wno-incompatible-pointer-types',
         '-Wno-missing-braces',
         '-Wno-unused-const-variable',
     ]
-
-if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
-    AllowCompilerWarnings()  # workaround for bug 1090497
--- a/accessible/interfaces/msaa/moz.build
+++ b/accessible/interfaces/msaa/moz.build
@@ -39,11 +39,8 @@ RCINCLUDE = 'AccessibleMarshal.rc'
 # Suppress warnings from the MIDL generated code.
 if CONFIG['CC_TYPE'] == 'clang-cl':
     CFLAGS += [
         '-Wno-extern-initializer',
         '-Wno-incompatible-pointer-types',
         '-Wno-missing-braces',
         '-Wno-unused-const-variable',
     ]
-
-if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
-    AllowCompilerWarnings()  # workaround for bug 1090497
--- a/browser/app/winlauncher/DllBlocklistWin.cpp
+++ b/browser/app/winlauncher/DllBlocklistWin.cpp
@@ -20,18 +20,17 @@
     /* Pointer to the buffer */ \
     const_cast<wchar_t*>(s) \
   }
 
 #define DLL_BLOCKLIST_ENTRY(name, ...) \
   { MOZ_LITERAL_UNICODE_STRING(L##name), __VA_ARGS__ },
 #define DLL_BLOCKLIST_STRING_TYPE UNICODE_STRING
 
-// Restrict the blocklist definitions to Nightly-only for now
-#if defined(NIGHTLY_BUILD)
+#if defined(MOZ_LAUNCHER_PROCESS) || defined(NIGHTLY_BUILD)
 #include "mozilla/WindowsDllBlocklistDefs.h"
 #else
 #include "mozilla/WindowsDllBlocklistCommon.h"
 DLL_BLOCKLIST_DEFINITIONS_BEGIN
 DLL_BLOCKLIST_DEFINITIONS_END
 #endif
 
 extern uint32_t gBlocklistInitFlags;
--- a/browser/app/winlauncher/LaunchUnelevated.cpp
+++ b/browser/app/winlauncher/LaunchUnelevated.cpp
@@ -1,32 +1,103 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 https://mozilla.org/MPL/2.0/. */
 
 #include "LaunchUnelevated.h"
 
+#include "mozilla/Assertions.h"
 #include "mozilla/CmdLineAndEnvUtils.h"
 #include "mozilla/mscom/COMApartmentRegion.h"
 #include "mozilla/RefPtr.h"
 #include "nsWindowsHelpers.h"
 
 // For _bstr_t and _variant_t
 #include <comdef.h>
 #include <comutil.h>
 
 #include <windows.h>
 #include <exdisp.h>
 #include <objbase.h>
 #include <servprov.h>
 #include <shlobj.h>
 #include <shobjidl.h>
 
+static mozilla::Maybe<TOKEN_ELEVATION_TYPE>
+GetElevationType(const nsAutoHandle& aToken)
+{
+  DWORD retLen;
+  TOKEN_ELEVATION_TYPE elevationType;
+  if (!::GetTokenInformation(aToken.get(), TokenElevationType, &elevationType,
+                             sizeof(elevationType), &retLen)) {
+    return mozilla::Nothing();
+  }
+
+  return mozilla::Some(elevationType);
+}
+
+static mozilla::Maybe<bool>
+IsHighIntegrity(const nsAutoHandle& aToken)
+{
+  DWORD reqdLen;
+  if (!::GetTokenInformation(aToken.get(), TokenIntegrityLevel, nullptr, 0,
+                             &reqdLen) &&
+      ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    return mozilla::Nothing();
+  }
+
+  auto buf = mozilla::MakeUnique<char[]>(reqdLen);
+
+  if (!::GetTokenInformation(aToken.get(), TokenIntegrityLevel, buf.get(),
+                             reqdLen, &reqdLen)) {
+    return mozilla::Nothing();
+  }
+
+  auto tokenLabel = reinterpret_cast<PTOKEN_MANDATORY_LABEL>(buf.get());
+
+  DWORD subAuthCount = *::GetSidSubAuthorityCount(tokenLabel->Label.Sid);
+  DWORD integrityLevel = *::GetSidSubAuthority(tokenLabel->Label.Sid,
+                                               subAuthCount - 1);
+  return mozilla::Some(integrityLevel > SECURITY_MANDATORY_MEDIUM_RID);
+}
+
+static nsReturnRef<HANDLE>
+GetMediumIntegrityToken(const nsAutoHandle& aProcessToken)
+{
+  nsAutoHandle empty;
+
+  HANDLE rawResult;
+  if (!::DuplicateTokenEx(aProcessToken.get(), 0, nullptr,
+                          SecurityImpersonation, TokenPrimary, &rawResult)) {
+    return empty.out();
+  }
+
+  nsAutoHandle result(rawResult);
+
+  BYTE mediumIlSid[SECURITY_MAX_SID_SIZE];
+  DWORD mediumIlSidSize = sizeof(mediumIlSid);
+  if (!::CreateWellKnownSid(WinMediumLabelSid, nullptr, mediumIlSid,
+                            &mediumIlSidSize)) {
+    return empty.out();
+  }
+
+  TOKEN_MANDATORY_LABEL integrityLevel = {};
+  integrityLevel.Label.Attributes = SE_GROUP_INTEGRITY;
+  integrityLevel.Label.Sid = reinterpret_cast<PSID>(mediumIlSid);
+
+  if (!::SetTokenInformation(rawResult, TokenIntegrityLevel, &integrityLevel,
+                             sizeof(integrityLevel))) {
+    return empty.out();
+  }
+
+  return result.out();
+}
+
 namespace mozilla {
 
 // If we're running at an elevated integrity level, re-run ourselves at the
 // user's normal integrity level. We do this by locating the active explorer
 // shell, and then asking it to do a ShellExecute on our behalf. We do it this
 // way to ensure that the child process runs as the original user in the active
 // session; an elevated process could be running with different credentials than
 // those of the session.
@@ -120,42 +191,68 @@ LaunchUnelevated(int aArgc, wchar_t* aAr
   _variant_t args(cmdLine.get());
   _variant_t operation(L"open");
   _variant_t directory;
   _variant_t showCmd(SW_SHOWNORMAL);
   hr = shellDisp->ShellExecute(exe, args, operation, directory, showCmd);
   return SUCCEEDED(hr);
 }
 
-mozilla::Maybe<bool>
-IsElevated()
+Maybe<ElevationState>
+GetElevationState(mozilla::LauncherFlags aFlags, nsAutoHandle& aOutMediumIlToken)
 {
+  aOutMediumIlToken.reset();
+
+  const DWORD tokenFlags = TOKEN_QUERY | TOKEN_DUPLICATE |
+                           TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY;
   HANDLE rawToken;
-  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
-    return mozilla::Nothing();
+  if (!::OpenProcessToken(::GetCurrentProcess(), tokenFlags, &rawToken)) {
+    return Nothing();
   }
 
   nsAutoHandle token(rawToken);
 
-  DWORD reqdLen;
-  if (!::GetTokenInformation(token.get(), TokenIntegrityLevel, nullptr, 0,
-                             &reqdLen) &&
-      ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
-    return mozilla::Nothing();
+  Maybe<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
+  if (!elevationType) {
+    return Nothing();
   }
 
-  auto buf = mozilla::MakeUnique<char[]>(reqdLen);
+  switch (elevationType.value()) {
+    case TokenElevationTypeLimited:
+      return Some(ElevationState::eNormalUser);
+    case TokenElevationTypeFull:
+      // If we want to start a non-elevated browser process and wait on it,
+      // we're going to need a medium IL token.
+      if ((aFlags & (mozilla::LauncherFlags::eWaitForBrowser |
+                     mozilla::LauncherFlags::eNoDeelevate)) ==
+          mozilla::LauncherFlags::eWaitForBrowser) {
+        aOutMediumIlToken = GetMediumIntegrityToken(token);
+      }
 
-  if (!::GetTokenInformation(token.get(), TokenIntegrityLevel, buf.get(),
-                             reqdLen, &reqdLen)) {
-    return mozilla::Nothing();
+      return Some(ElevationState::eElevated);
+    case TokenElevationTypeDefault:
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Was a new value added to the enumeration?");
+      return Nothing();
   }
 
-  auto tokenLabel = reinterpret_cast<PTOKEN_MANDATORY_LABEL>(buf.get());
+  // In this case, UAC is disabled. We do not yet know whether or not we are
+  // running at high integrity. If we are at high integrity, we can't relaunch
+  // ourselves in a non-elevated state via Explorer, as we would just end up in
+  // an infinite loop of launcher processes re-launching themselves.
 
-  DWORD subAuthCount = *::GetSidSubAuthorityCount(tokenLabel->Label.Sid);
-  DWORD integrityLevel = *::GetSidSubAuthority(tokenLabel->Label.Sid,
-                                               subAuthCount - 1);
-  return mozilla::Some(integrityLevel > SECURITY_MANDATORY_MEDIUM_RID);
+  Maybe<bool> isHighIntegrity = IsHighIntegrity(token);
+  if (!isHighIntegrity) {
+    return Nothing();
+  }
+
+  if (!isHighIntegrity.value()) {
+    return Some(ElevationState::eNormalUser);
+  }
+
+  aOutMediumIlToken = GetMediumIntegrityToken(token);
+
+  return Some(ElevationState::eHighIntegrityNoUAC);
 }
 
 } // namespace mozilla
 
--- a/browser/app/winlauncher/LaunchUnelevated.h
+++ b/browser/app/winlauncher/LaunchUnelevated.h
@@ -2,19 +2,30 @@
 /* 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 https://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_LaunchUnelevated_h
 #define mozilla_LaunchUnelevated_h
 
+#include "LauncherProcessWin.h"
 #include "mozilla/Maybe.h"
+#include "nsWindowsHelpers.h"
 
 namespace mozilla {
 
-mozilla::Maybe<bool> IsElevated();
+enum class ElevationState
+{
+  eNormalUser = 0,
+  eElevated = (1 << 0),
+  eHighIntegrityNoUAC = (1 << 1),
+};
+
+mozilla::Maybe<ElevationState>
+GetElevationState(LauncherFlags aFlags, nsAutoHandle& aOutMediumIlToken);
+
 bool LaunchUnelevated(int aArgc, wchar_t* aArgv[]);
 
 } // namespace mozilla
 
 #endif // mozilla_LaunchUnelevated_h
 
--- a/browser/app/winlauncher/LauncherProcessWin.cpp
+++ b/browser/app/winlauncher/LauncherProcessWin.cpp
@@ -77,26 +77,92 @@ ShowError(DWORD aError = ::GetLastError(
   if (!result) {
     return;
   }
 
   ::MessageBoxW(nullptr, rawMsgBuf, L"Firefox", MB_OK | MB_ICONERROR);
   ::LocalFree(rawMsgBuf);
 }
 
+static mozilla::LauncherFlags
+ProcessCmdLine(int& aArgc, wchar_t* aArgv[])
+{
+  mozilla::LauncherFlags result = mozilla::LauncherFlags::eNone;
+
+  if (mozilla::CheckArg(aArgc, aArgv, L"wait-for-browser",
+                        static_cast<const wchar_t**>(nullptr),
+                        mozilla::CheckArgFlag::RemoveArg) == mozilla::ARG_FOUND ||
+      mozilla::EnvHasValue("MOZ_AUTOMATION")) {
+    result |= mozilla::LauncherFlags::eWaitForBrowser;
+  }
+
+  if (mozilla::CheckArg(aArgc, aArgv, L"no-deelevate",
+                        static_cast<const wchar_t**>(nullptr),
+                        mozilla::CheckArgFlag::CheckOSInt |
+                        mozilla::CheckArgFlag::RemoveArg) == mozilla::ARG_FOUND) {
+    result |= mozilla::LauncherFlags::eNoDeelevate;
+  }
+
+  return result;
+}
+
+#if defined(MOZ_LAUNCHER_PROCESS)
+
+static mozilla::Maybe<bool>
+IsSameBinaryAsParentProcess()
+{
+  mozilla::Maybe<DWORD> parentPid = mozilla::nt::GetParentProcessId();
+  if (!parentPid) {
+    return mozilla::Nothing();
+  }
+
+  nsAutoHandle parentProcess(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
+                                           FALSE, parentPid.value()));
+  if (!parentProcess.get()) {
+    return mozilla::Nothing();
+  }
+
+  WCHAR parentExe[MAX_PATH + 1] = {};
+  DWORD parentExeLen = mozilla::ArrayLength(parentExe);
+  if (!::QueryFullProcessImageNameW(parentProcess.get(), 0, parentExe,
+                                    &parentExeLen)) {
+    return mozilla::Nothing();
+  }
+
+  WCHAR ourExe[MAX_PATH + 1] = {};
+  DWORD ourExeOk = ::GetModuleFileNameW(nullptr, ourExe,
+                                        mozilla::ArrayLength(ourExe));
+  if (!ourExeOk || ourExeOk == mozilla::ArrayLength(ourExe)) {
+    return mozilla::Nothing();
+  }
+
+  bool isSame = parentExeLen == ourExeOk &&
+                !_wcsnicmp(ourExe, parentExe, ourExeOk);
+  return mozilla::Some(isSame);
+}
+
+#endif // defined(MOZ_LAUNCHER_PROCESS)
+
 namespace mozilla {
 
-// Eventually we want to be able to set a build config flag such that, when set,
-// this function will always return true.
 bool
 RunAsLauncherProcess(int& argc, wchar_t** argv)
 {
+#if defined(MOZ_LAUNCHER_PROCESS)
+  Maybe<bool> isChildOfFirefox = IsSameBinaryAsParentProcess();
+  if (!isChildOfFirefox) {
+    return true;
+  }
+
+  return !isChildOfFirefox.value();
+#else
   return CheckArg(argc, argv, L"launcher",
                   static_cast<const wchar_t**>(nullptr),
-                  CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
+                  CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg) == ARG_FOUND;
+#endif // defined(MOZ_LAUNCHER_PROCESS)
 }
 
 int
 LauncherMain(int argc, wchar_t* argv[])
 {
   // Make sure that the launcher process itself has image load policies set
   if (IsWin10AnniversaryUpdateOrLater()) {
     const DynamicallyLinkedFunctionPtr<decltype(&SetProcessMitigationPolicy)>
@@ -112,23 +178,30 @@ LauncherMain(int argc, wchar_t* argv[])
     }
   }
 
   if (!SetArgv0ToFullBinaryPath(argv)) {
     ShowError();
     return 1;
   }
 
-  // If we're elevated, we should relaunch ourselves as a normal user
-  Maybe<bool> isElevated = IsElevated();
-  if (!isElevated) {
+  LauncherFlags flags = ProcessCmdLine(argc, argv);
+
+  nsAutoHandle mediumIlToken;
+  Maybe<ElevationState> elevationState = GetElevationState(flags, mediumIlToken);
+  if (!elevationState) {
     return 1;
   }
 
-  if (isElevated.value()) {
+  // If we're elevated, we should relaunch ourselves as a normal user.
+  // Note that we only call LaunchUnelevated when we don't need to wait for the
+  // browser process.
+  if (elevationState.value() == ElevationState::eElevated &&
+      !(flags & (LauncherFlags::eWaitForBrowser | LauncherFlags::eNoDeelevate)) &&
+      !mediumIlToken.get()) {
     return !LaunchUnelevated(argc, argv);
   }
 
   // Now proceed with setting up the parameters for process creation
   UniquePtr<wchar_t[]> cmdLine(MakeCommandLine(argc, argv));
   if (!cmdLine) {
     return 1;
   }
@@ -173,36 +246,57 @@ LauncherMain(int argc, wchar_t* argv[])
 
       // Since attrsOk == true, we have successfully set the handle inheritance
       // whitelist policy, so only the handles added to attrs will be inherited.
       inheritHandles = TRUE;
     }
   }
 
   PROCESS_INFORMATION pi = {};
-  if (!::CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr, inheritHandles,
-                        creationFlags, nullptr, nullptr, &siex.StartupInfo, &pi)) {
+  BOOL createOk;
+
+  if (mediumIlToken.get()) {
+    createOk = ::CreateProcessAsUserW(mediumIlToken.get(), argv[0], cmdLine.get(),
+                                      nullptr, nullptr, inheritHandles,
+                                      creationFlags, nullptr, nullptr,
+                                      &siex.StartupInfo, &pi);
+  } else {
+    createOk = ::CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr,
+                                inheritHandles, creationFlags, nullptr, nullptr,
+                                &siex.StartupInfo, &pi);
+  }
+
+  if (!createOk) {
     ShowError();
     return 1;
   }
 
   nsAutoHandle process(pi.hProcess);
   nsAutoHandle mainThread(pi.hThread);
 
   if (!PostCreationSetup(process.get(), mainThread.get(), isSafeMode.value()) ||
       ::ResumeThread(mainThread.get()) == static_cast<DWORD>(-1)) {
     ShowError();
     ::TerminateProcess(process.get(), 1);
     return 1;
   }
 
-  const DWORD timeout = ::IsDebuggerPresent() ? INFINITE :
-                        kWaitForInputIdleTimeoutMS;
+  if (flags & LauncherFlags::eWaitForBrowser) {
+    DWORD exitCode;
+    if (::WaitForSingleObject(process.get(), INFINITE) == WAIT_OBJECT_0 &&
+        ::GetExitCodeProcess(process.get(), &exitCode)) {
+      // Propagate the browser process's exit code as our exit code.
+      return static_cast<int>(exitCode);
+    }
+  } else {
+    const DWORD timeout = ::IsDebuggerPresent() ? INFINITE :
+                          kWaitForInputIdleTimeoutMS;
 
-  // Keep the current process around until the callback process has created
-  // its message queue, to avoid the launched process's windows being forced
-  // into the background.
-  mozilla::WaitForInputIdle(process.get(), timeout);
+    // Keep the current process around until the callback process has created
+    // its message queue, to avoid the launched process's windows being forced
+    // into the background.
+    mozilla::WaitForInputIdle(process.get(), timeout);
+  }
 
   return 0;
 }
 
 } // namespace mozilla
--- a/browser/app/winlauncher/LauncherProcessWin.h
+++ b/browser/app/winlauncher/LauncherProcessWin.h
@@ -2,17 +2,30 @@
 /* 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 https://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_LauncherProcessWin_h
 #define mozilla_LauncherProcessWin_h
 
+#include "mozilla/TypedEnumBits.h"
+
+#include <stdint.h>
+
 namespace mozilla {
 
 bool RunAsLauncherProcess(int& argc, wchar_t* argv[]);
 int LauncherMain(int argc, wchar_t* argv[]);
 
+enum class LauncherFlags : uint32_t
+{
+  eNone = 0,
+  eWaitForBrowser = (1 << 0), // Launcher should block until browser finishes
+  eNoDeelevate = (1 << 1),    // If elevated, do not attempt to de-elevate
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(LauncherFlags)
+
 } // namespace mozilla
 
 #endif // mozilla_LauncherProcessWin_h
 
--- a/browser/app/winlauncher/NativeNt.h
+++ b/browser/app/winlauncher/NativeNt.h
@@ -13,16 +13,17 @@
 
 #include <stdint.h>
 #include <windows.h>
 #include <winnt.h>
 #include <winternl.h>
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
 
 extern "C" {
 
 #if !defined(STATUS_ACCESS_DENIED)
 #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
 #endif // !defined(STATUS_ACCESS_DENIED)
 
 #if !defined(STATUS_DLL_NOT_FOUND)
@@ -444,18 +445,25 @@ private:
       return;
     }
 
     mPeHeader = RVAToPtrUnchecked<PIMAGE_NT_HEADERS>(mMzHeader->e_lfanew);
     if (!mPeHeader || mPeHeader->Signature != IMAGE_NT_SIGNATURE) {
       return;
     }
 
+    DWORD imageSize = mPeHeader->OptionalHeader.SizeOfImage;
+    // This is a coarse-grained check to ensure that the image size is
+    // reasonable. It we aren't big enough to contain headers, we have a problem!
+    if (imageSize < sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS)) {
+      return;
+    }
+
     mImageLimit =
-      RVAToPtrUnchecked<void*>(mPeHeader->OptionalHeader.SizeOfImage - 1UL);
+      RVAToPtrUnchecked<void*>(imageSize - 1UL);
   }
 
   template <typename T>
   T GetImageDirectoryEntry(unsigned int aDirectoryIndex)
   {
     if (aDirectoryIndex >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) {
       return nullptr;
     }
@@ -506,34 +514,40 @@ private:
 
     return dirEnt;
   }
 
   VS_FIXEDFILEINFO*
   GetFixedFileInfo(VS_VERSIONINFO_HEADER* aVerInfo)
   {
     WORD length = aVerInfo->wLength;
-    WORD offset = sizeof(VS_VERSIONINFO_HEADER);
-    if (!offset) {
+    if (length < sizeof(VS_VERSIONINFO_HEADER)) {
       return nullptr;
     }
 
     const wchar_t kVersionInfoKey[] = L"VS_VERSION_INFO";
     if (::RtlCompareMemory(aVerInfo->szKey, kVersionInfoKey,
                            ArrayLength(kVersionInfoKey)) !=
         ArrayLength(kVersionInfoKey)) {
       return nullptr;
     }
 
+    if (aVerInfo->wValueLength != sizeof(VS_FIXEDFILEINFO)) {
+      // Fixed file info does not exist
+      return nullptr;
+    }
+
+    WORD offset = sizeof(VS_VERSIONINFO_HEADER);
+
     uintptr_t base = reinterpret_cast<uintptr_t>(aVerInfo);
     // Align up to 4-byte boundary
 #pragma warning(suppress: 4146)
     offset += (-(base + offset) & 3);
 
-    if (offset > length) {
+    if (offset >= length) {
       return nullptr;
     }
 
     auto result = reinterpret_cast<VS_FIXEDFILEINFO*>(base + offset);
     if (result->dwSignature != 0xFEEF04BD) {
       return nullptr;
     }
 
@@ -549,12 +563,38 @@ private:
 inline HANDLE
 RtlGetProcessHeap()
 {
   PTEB teb = ::NtCurrentTeb();
   PPEB peb = teb->ProcessEnvironmentBlock;
   return peb->Reserved4[1];
 }
 
+inline Maybe<DWORD>
+GetParentProcessId()
+{
+  struct PROCESS_BASIC_INFORMATION
+  {
+    NTSTATUS ExitStatus;
+    PPEB PebBaseAddress;
+    ULONG_PTR AffinityMask;
+    LONG BasePriority;
+    ULONG_PTR UniqueProcessId;
+    ULONG_PTR InheritedFromUniqueProcessId;
+  };
+
+  ULONG returnLength;
+  PROCESS_BASIC_INFORMATION pbi = {};
+  NTSTATUS status = ::NtQueryInformationProcess(::GetCurrentProcess(),
+                                                ProcessBasicInformation,
+                                                &pbi, sizeof(pbi),
+                                                &returnLength);
+  if (!NT_SUCCESS(status)) {
+    return Nothing();
+  }
+
+  return Some(static_cast<DWORD>(pbi.InheritedFromUniqueProcessId & 0xFFFFFFFF));
+}
+
 } // namespace nt
 } // namespace mozilla
 
 #endif // mozilla_NativeNt_h
--- a/browser/components/places/tests/browser/browser_views_iconsupdate.js
+++ b/browser/components/places/tests/browser/browser_views_iconsupdate.js
@@ -103,17 +103,20 @@ function getNodeForToolbarItem(guid) {
  * @param guid
  *        GUID of the item to search.
  * @returns DOM Node of the element.
  */
 async function getRectForSidebarItem(guid) {
   let sidebar = document.getElementById("sidebar");
   let tree = sidebar.contentDocument.getElementById("bookmarks-view");
   tree.selectItems([guid]);
-  let rect = {};
-  [rect.left, rect.top, rect.width, rect.height] = tree.treeBoxObject
-                                                       .selectionRegion
-                                                       .getRects();
-  // Adjust the position for the sidebar.
-  rect.left += sidebar.getBoundingClientRect().left;
-  rect.top += sidebar.getBoundingClientRect().top;
-  return rect;
+  let treerect = tree.getBoundingClientRect();
+  let cellrect = tree.treeBoxObject.
+                      getCoordsForCellItem(tree.currentIndex, tree.columns[0], "cell");
+
+  // Adjust the position for the tree and sidebar.
+  return {
+    left: treerect.left + cellrect.left + sidebar.getBoundingClientRect().left,
+    top: treerect.top + cellrect.top + sidebar.getBoundingClientRect().top,
+    width: cellrect.width,
+    height: cellrect.height
+  };
 }
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -1262,16 +1262,17 @@ def pgo_flags(compiler, build_env, targe
     if compiler.type == 'clang-cl':
         profdata = os.path.join(topobjdir, 'merged.profdata')
         # 32-bit PGO is currently blocked by bug 1479800
         if target.cpu == 'x86_64':
           return namespace(
               gen_cflags=['-fprofile-instr-generate'],
               gen_ldflags=['clang_rt.profile-x86_64.lib'],
               use_cflags=['-fprofile-instr-use=%s' % profdata,
+                          '-Wno-error=profile-instr-out-of-date',
                           '-Wno-error=profile-instr-unprofiled'],
               use_ldflags=[],
           )
 
     if compiler.type == 'msvc':
         num_cores = min(8, multiprocessing.cpu_count())
         cgthreads = '-CGTHREADS:%s' % num_cores
 
--- a/build/unix/elfhack/elfhack.cpp
+++ b/build/unix/elfhack/elfhack.cpp
@@ -1074,18 +1074,21 @@ int do_relocation_section(Elf *elf, unsi
         fprintf(stderr, "Couldn't find executable section. Skipping\n");
         return -1;
     }
 
     relhack->insertBefore(section);
     relhackcode->insertBefore(first_executable);
 
     // Don't try further if we can't gain from the relocation section size change.
+    // We account for the fact we're going to split the PT_LOAD before the injected
+    // code section, so the overhead of the page alignment for section needs to be
+    // accounted for.
     size_t align = first_executable->getSegmentByType(PT_LOAD)->getAlign();
-    size_t new_size = relhack->getSize() + relhackcode->getSize();
+    size_t new_size = relhack->getSize() + relhackcode->getSize() + (relhackcode->getAddr() & (align - 1));
     if (!force && (new_size >= old_size || old_size - new_size < align)) {
         fprintf(stderr, "No gain. Skipping\n");
         return -1;
     }
 
     // .eh_frame/.eh_frame_hdr may be between the relocation sections and the
     // executable sections. When that happens, we may end up creating a separate
     // PT_LOAD for just both of them because they are not considered relocatable.
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -1627,16 +1627,156 @@ exports.CSS_PROPERTIES = {
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
   },
+  "-webkit-appearance": {
+    "isInherited": false,
+    "subproperties": [
+      "-moz-appearance"
+    ],
+    "supports": [],
+    "values": [
+      "-moz-gtk-info-bar",
+      "-moz-mac-active-source-list-selection",
+      "-moz-mac-disclosure-button-closed",
+      "-moz-mac-disclosure-button-open",
+      "-moz-mac-fullscreen-button",
+      "-moz-mac-help-button",
+      "-moz-mac-source-list",
+      "-moz-mac-source-list-selection",
+      "-moz-mac-vibrancy-dark",
+      "-moz-mac-vibrancy-light",
+      "-moz-mac-vibrant-titlebar-dark",
+      "-moz-mac-vibrant-titlebar-light",
+      "-moz-menulist-button",
+      "-moz-win-borderless-glass",
+      "-moz-win-browsertabbar-toolbox",
+      "-moz-win-communications-toolbox",
+      "-moz-win-exclude-glass",
+      "-moz-win-glass",
+      "-moz-win-media-toolbox",
+      "-moz-window-button-box",
+      "-moz-window-button-box-maximized",
+      "-moz-window-button-close",
+      "-moz-window-button-maximize",
+      "-moz-window-button-minimize",
+      "-moz-window-button-restore",
+      "-moz-window-frame-bottom",
+      "-moz-window-frame-left",
+      "-moz-window-frame-right",
+      "-moz-window-titlebar",
+      "-moz-window-titlebar-maximized",
+      "button",
+      "button-arrow-down",
+      "button-arrow-next",
+      "button-arrow-previous",
+      "button-arrow-up",
+      "button-bevel",
+      "button-focus",
+      "caret",
+      "checkbox",
+      "checkbox-container",
+      "checkbox-label",
+      "checkmenuitem",
+      "dialog",
+      "dualbutton",
+      "groupbox",
+      "inherit",
+      "initial",
+      "inner-spin-button",
+      "listbox",
+      "listitem",
+      "menuarrow",
+      "menubar",
+      "menucheckbox",
+      "menuimage",
+      "menuitem",
+      "menuitemtext",
+      "menulist",
+      "menulist-button",
+      "menulist-text",
+      "menulist-textfield",
+      "menupopup",
+      "menuradio",
+      "menuseparator",
+      "meterbar",
+      "meterchunk",
+      "none",
+      "number-input",
+      "progressbar",
+      "progressbar-vertical",
+      "progresschunk",
+      "progresschunk-vertical",
+      "radio",
+      "radio-container",
+      "radio-label",
+      "radiomenuitem",
+      "range",
+      "range-thumb",
+      "resizer",
+      "resizerpanel",
+      "scale-horizontal",
+      "scale-vertical",
+      "scalethumb-horizontal",
+      "scalethumb-vertical",
+      "scalethumbend",
+      "scalethumbstart",
+      "scalethumbtick",
+      "scrollbar",
+      "scrollbar-horizontal",
+      "scrollbar-small",
+      "scrollbar-vertical",
+      "scrollbarbutton-down",
+      "scrollbarbutton-left",
+      "scrollbarbutton-right",
+      "scrollbarbutton-up",
+      "scrollbarthumb-horizontal",
+      "scrollbarthumb-vertical",
+      "scrollbartrack-horizontal",
+      "scrollbartrack-vertical",
+      "scrollcorner",
+      "searchfield",
+      "separator",
+      "spinner",
+      "spinner-downbutton",
+      "spinner-textfield",
+      "spinner-upbutton",
+      "splitter",
+      "statusbar",
+      "statusbarpanel",
+      "tab",
+      "tab-scroll-arrow-back",
+      "tab-scroll-arrow-forward",
+      "tabpanel",
+      "tabpanels",
+      "textfield",
+      "textfield-multiline",
+      "toolbar",
+      "toolbarbutton",
+      "toolbarbutton-dropdown",
+      "toolbargripper",
+      "toolbox",
+      "tooltip",
+      "treeheader",
+      "treeheadercell",
+      "treeheadersortarrow",
+      "treeitem",
+      "treeline",
+      "treetwisty",
+      "treetwistyopen",
+      "treeview",
+      "unset",
+      "window"
+    ]
+  },
   "-webkit-backface-visibility": {
     "isInherited": false,
     "subproperties": [
       "backface-visibility"
     ],
     "supports": [],
     "values": [
       "hidden",
--- a/devtools/shared/webconsole/test/test_bug819670_getter_throws.html
+++ b/devtools/shared/webconsole/test/test_bug819670_getter_throws.html
@@ -46,17 +46,16 @@ function onEvaluate(aState, aResponse)
 }
 
 function onInspect(aState, aResponse)
 {
   ok(!aResponse.error, "no response error");
 
   let expectedProps = {
     "addBroadcastListenerFor": { value: { type: "object" } },
-    "commandDispatcher": { get: { type: "object" } },
   };
 
   let props = aResponse.ownProperties;
   ok(props, "response properties available");
 
   if (props) {
     ok(Object.keys(props).length > Object.keys(expectedProps).length,
        "number of enumerable properties");
--- a/dom/base/UseCounters.conf
+++ b/dom/base/UseCounters.conf
@@ -119,8 +119,10 @@ method console.timeEnd
 method console.exception
 method console.timeStamp
 method console.profile
 method console.profileEnd
 
 // document.open information
 custom DocumentOpen calls document.open in a way that creates a new Window object
 custom DocumentOpenReplace calls document.open in a way that creates a new Window object and replaces the old history entry.
+
+custom FilteredCrossOriginIFrame cross-origin <iframe> within a CSS/SVG filter
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -254,16 +254,17 @@
 #include "mozilla/dom/SVGDocument.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 #ifdef MOZ_XUL
 #include "mozilla/dom/MenuBoxObject.h"
 #include "mozilla/dom/TreeBoxObject.h"
 #include "nsIXULWindow.h"
+#include "nsXULCommandDispatcher.h"
 #include "nsXULPopupManager.h"
 #include "nsIDocShellTreeOwner.h"
 #endif
 #include "nsIPresShellInlines.h"
 
 #include "mozilla/DocLoadingTimelineMarker.h"
 
 #include "nsISpeculativeConnect.h"
@@ -1919,16 +1920,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImages);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEmbeds);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLinks);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mForms);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScripts);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
 
   // Traverse all our nsCOMArrays.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
 
   for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
     cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
@@ -2009,16 +2011,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLinks);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mForms);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScripts);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplets);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchors);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher)
 
   tmp->mParentDocument = nullptr;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntersectionObservers)
 
   tmp->ClearAllBoxObjects();
@@ -10144,16 +10147,30 @@ nsIDocument::MaybeResolveReadyForIdle()
 {
   IgnoredErrorResult rv;
   Promise* readyPromise = GetDocumentReadyForIdle(rv);
   if (readyPromise) {
     readyPromise->MaybeResolve(this);
   }
 }
 
+nsIDOMXULCommandDispatcher*
+nsIDocument::GetCommandDispatcher()
+{
+  // Only chrome documents are allowed to use command dispatcher.
+  if (!nsContentUtils::IsChromeDoc(this)) {
+    return nullptr;
+  }
+  if (!mCommandDispatcher) {
+    // Create our command dispatcher and hook it up.
+    mCommandDispatcher = new nsXULCommandDispatcher(this);
+  }
+  return mCommandDispatcher;
+}
+
 static JSObject*
 GetScopeObjectOfNode(nsINode* node)
 {
     MOZ_ASSERT(node, "Must not be called with null.");
 
     // Window root occasionally keeps alive a node of a document whose
     // window is already dead. If in this brief period someone calls
     // GetPopupNode and we return that node, we can end up creating a
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -6262,26 +6262,26 @@ nsGlobalWindowOuter::UpdateCommands(cons
   }
 
   nsPIDOMWindowOuter *rootWindow = GetPrivateRoot();
   if (!rootWindow) {
     return;
   }
 
   nsIDocument* doc = rootWindow->GetExtantDoc();
-  // See if we contain a XUL document.
-  if (!doc || !doc->IsXULDocument()) {
+
+  if (!doc) {
     return;
   }
   // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
   // XUL command dispatch if anAction is "selectionchange".
   if (!anAction.EqualsLiteral("selectionchange")) {
     // Retrieve the command dispatcher and call updateCommands on it.
     nsIDOMXULCommandDispatcher* xulCommandDispatcher =
-      doc->AsXULDocument()->GetCommandDispatcher();
+      doc->GetCommandDispatcher();
     if (xulCommandDispatcher) {
       nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
                                                             anAction));
     }
   }
 }
 
 Selection*
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -10,16 +10,17 @@
 #include "nsAutoPtr.h"                   // for member
 #include "nsCOMArray.h"                  // for member
 #include "nsCompatibility.h"             // for member
 #include "nsCOMPtr.h"                    // for member
 #include "nsGkAtoms.h"                   // for static class members
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheContainer.h"
 #include "nsIContentViewer.h"
+#include "nsIDOMXULCommandDispatcher.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILoadContext.h"
 #include "nsILoadGroup.h"                // for member (in nsCOMPtr)
 #include "nsINode.h"                     // for base class
 #include "nsIParser.h"
 #include "nsIPresShell.h"
 #include "nsIChannelEventSink.h"
 #include "nsIProgressEventSink.h"
@@ -3319,16 +3320,17 @@ public:
   already_AddRefed<mozilla::dom::Promise> BlockParsing(mozilla::dom::Promise& aPromise,
                                                        const mozilla::dom::BlockParsingOptions& aOptions,
                                                        mozilla::ErrorResult& aRv);
 
   already_AddRefed<nsIURI> GetMozDocumentURIIfNotForErrorPages();
 
   mozilla::dom::Promise* GetDocumentReadyForIdle(mozilla::ErrorResult& aRv);
 
+  nsIDOMXULCommandDispatcher* GetCommandDispatcher();
   already_AddRefed<nsINode> GetPopupNode();
   void SetPopupNode(nsINode* aNode);
   nsINode* GetPopupRangeParent(ErrorResult& aRv);
   int32_t GetPopupRangeOffset(ErrorResult& aRv);
   already_AddRefed<nsINode> GetTooltipNode();
   void SetTooltipNode(nsINode* aNode) { /* do nothing */ }
 
   // ParentNode
@@ -4492,16 +4494,18 @@ protected:
 
   // Used in conjunction with the create-an-element-for-the-token algorithm to
   // prevent custom element constructors from being able to use document.open(),
   // document.close(), and document.write() when they are invoked by the parser.
   uint32_t mThrowOnDynamicMarkupInsertionCounter;
 
   // Count of unload/beforeunload/pagehide operations in progress.
   uint32_t mIgnoreOpensDuringUnloadCounter;
+
+  nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
 /**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -76,16 +76,25 @@ static void PrintReqURL(imgIRequest* req
   }
 
   nsAutoCString spec;
   uri->GetSpec(spec);
   printf("spec='%s'\n", spec.get());
 }
 #endif /* DEBUG_chb */
 
+const nsAttrValue::EnumTable nsImageLoadingContent::kDecodingTable[] = {
+  { "auto",   nsImageLoadingContent::ImageDecodingType::Auto },
+  { "async",  nsImageLoadingContent::ImageDecodingType::Async },
+  { "sync",   nsImageLoadingContent::ImageDecodingType::Sync },
+  { nullptr,  0 }
+};
+
+const nsAttrValue::EnumTable* nsImageLoadingContent::kDecodingTableDefault =
+  &nsImageLoadingContent::kDecodingTable[0];
 
 nsImageLoadingContent::nsImageLoadingContent()
   : mCurrentRequestFlags(0),
     mPendingRequestFlags(0),
     mObserverList(nullptr),
     mImageBlockingStatus(nsIContentPolicy::ACCEPT),
     mLoadingEnabled(true),
     mIsImageStateForced(false),
@@ -94,17 +103,18 @@ nsImageLoadingContent::nsImageLoadingCon
     mBroken(true),
     mUserDisabled(false),
     mSuppressed(false),
     mNewRequestsWillNeedAnimationReset(false),
     mUseUrgentStartForChannel(false),
     mStateChangerDepth(0),
     mCurrentRequestRegistered(false),
     mPendingRequestRegistered(false),
-    mIsStartingImageLoad(false)
+    mIsStartingImageLoad(false),
+    mSyncDecodingHint(false)
 {
   if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
     mLoadingEnabled = false;
   }
 
   mMostRecentRequestChange = TimeStamp::ProcessCreation();
 }
 
@@ -330,16 +340,60 @@ nsImageLoadingContent::OnImageIsAnimated
 void
 nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
 {
   if (nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
     mLoadingEnabled = aLoadingEnabled;
   }
 }
 
+void
+nsImageLoadingContent::SetSyncDecodingHint(bool aHint)
+{
+  if (mSyncDecodingHint == aHint) {
+    return;
+  }
+
+  mSyncDecodingHint = aHint;
+  MaybeForceSyncDecoding(/* aPrepareNextRequest */ false);
+}
+
+void
+nsImageLoadingContent::MaybeForceSyncDecoding(bool aPrepareNextRequest,
+                                              nsIFrame* aFrame /* = nullptr */)
+{
+  nsIFrame* frame = aFrame ? aFrame : GetOurPrimaryFrame();
+  nsImageFrame* imageFrame = do_QueryFrame(frame);
+  nsSVGImageFrame* svgImageFrame = do_QueryFrame(frame);
+  if (!imageFrame && !svgImageFrame) {
+    return;
+  }
+
+  bool forceSync = mSyncDecodingHint;
+  if (!forceSync && aPrepareNextRequest) {
+    // Detect JavaScript-based animations created by changing the |src|
+    // attribute on a timer.
+    TimeStamp now = TimeStamp::Now();
+    TimeDuration threshold =
+      TimeDuration::FromMilliseconds(
+        gfxPrefs::ImageInferSrcAnimationThresholdMS());
+
+    // If the length of time between request changes is less than the threshold,
+    // then force sync decoding to eliminate flicker from the animation.
+    forceSync = (now - mMostRecentRequestChange < threshold);
+    mMostRecentRequestChange = now;
+  }
+
+  if (imageFrame) {
+    imageFrame->SetForceSyncDecoding(forceSync);
+  } else {
+    svgImageFrame->SetForceSyncDecoding(forceSync);
+  }
+}
+
 NS_IMETHODIMP
 nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus)
 {
   MOZ_ASSERT(aStatus, "Null out param");
   *aStatus = ImageBlockingStatus();
   return NS_OK;
 }
 
@@ -624,16 +678,17 @@ nsImageLoadingContent::GetRequest(int32_
   return result.StealNSResult();
 }
 
 NS_IMETHODIMP_(void)
 nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
 {
   NS_ASSERTION(aFrame, "aFrame is null");
 
+  MaybeForceSyncDecoding(/* aPrepareNextRequest */ false, aFrame);
   TrackImage(mCurrentRequest, aFrame);
   TrackImage(mPendingRequest, aFrame);
 
   // We need to make sure that our image request is registered, if it should
   // be registered.
   nsPresContext* presContext = aFrame->PresContext();
   if (mCurrentRequest) {
     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mCurrentRequest,
@@ -1258,37 +1313,17 @@ nsImageLoadingContent::CancelPendingEven
     mPendingEvent->Cancel();
     mPendingEvent = nullptr;
   }
 }
 
 RefPtr<imgRequestProxy>&
 nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
 {
-  nsImageFrame* imageFrame = do_QueryFrame(GetOurPrimaryFrame());
-  nsSVGImageFrame* svgImageFrame = do_QueryFrame(GetOurPrimaryFrame());
-  if (imageFrame || svgImageFrame) {
-    // Detect JavaScript-based animations created by changing the |src|
-    // attribute on a timer.
-    TimeStamp now = TimeStamp::Now();
-    TimeDuration threshold =
-      TimeDuration::FromMilliseconds(
-        gfxPrefs::ImageInferSrcAnimationThresholdMS());
-
-    // If the length of time between request changes is less than the threshold,
-    // then force sync decoding to eliminate flicker from the animation.
-    bool forceSync = (now - mMostRecentRequestChange < threshold);
-    if (imageFrame) {
-      imageFrame->SetForceSyncDecoding(forceSync);
-    } else {
-      svgImageFrame->SetForceSyncDecoding(forceSync);
-    }
-
-    mMostRecentRequestChange = now;
-  }
+  MaybeForceSyncDecoding(/* aPrepareNextRequest */ true);
 
   // We only want to cancel the existing current request if size is not
   // available. bz says the web depends on this behavior.
   // Otherwise, we get rid of any half-baked request that might be sitting there
   // and make this one current.
   return HaveSize(mCurrentRequest) ?
            PreparePendingRequest(aImageLoadType) :
            PrepareCurrentRequest(aImageLoadType);
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -19,16 +19,17 @@
 #include "mozilla/TimeStamp.h"
 #include "nsCOMPtr.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIRequest.h"
 #include "mozilla/ErrorResult.h"
 #include "nsIContentPolicy.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/net/ReferrerPolicy.h"
+#include "nsAttrValue.h"
 
 class nsIURI;
 class nsIDocument;
 class nsPresContext;
 class nsIContent;
 class imgRequestProxy;
 
 namespace mozilla {
@@ -75,16 +76,21 @@ public:
   int32_t
     GetRequestType(imgIRequest* aRequest, mozilla::ErrorResult& aError);
   already_AddRefed<nsIURI> GetCurrentURI(mozilla::ErrorResult& aError);
   already_AddRefed<nsIURI> GetCurrentRequestFinalURI();
   void ForceReload(bool aNotify, mozilla::ErrorResult& aError);
 
   mozilla::dom::Element* FindImageMap();
 
+  /**
+   * Toggle whether or not to synchronously decode an image on draw.
+   */
+  void SetSyncDecodingHint(bool aHint);
+
 protected:
   enum ImageLoadType {
     // Most normal image loads
     eImageLoadType_Normal,
     // From a <img srcset> or <picture> context. Affects type given to content
     // policy.
     eImageLoadType_Imageset
   };
@@ -223,16 +229,25 @@ protected:
   static nsContentPolicyType PolicyTypeForLoad(ImageLoadType aImageLoadType);
 
   void AsyncEventRunning(mozilla::AsyncEventDispatcher* aEvent);
 
   // Get ourselves as an nsIContent*.  Not const because some of the callers
   // want a non-const nsIContent.
   virtual nsIContent* AsContent() = 0;
 
+  enum class ImageDecodingType : uint8_t {
+    Auto,
+    Async,
+    Sync,
+  };
+
+  static const nsAttrValue::EnumTable kDecodingTable[];
+  static const nsAttrValue::EnumTable* kDecodingTableDefault;
+
 private:
   /**
    * Struct used to manage the native image observers.
    */
   struct ImageObserver {
     explicit ImageObserver(imgINotificationObserver* aObserver);
     ~ImageObserver();
 
@@ -439,16 +454,29 @@ private:
   /**
    * Moves the "pending" request into the "current" request for each scripted
    * observer. If there is an existing "current" request, it will cancel it
    * first.
    */
   void MakePendingScriptedRequestsCurrent();
 
   /**
+   * Depending on the configured decoding hint, and/or how recently we updated
+   * the image request, force or stop the frame from decoding the image
+   * synchronously when it is drawn.
+   * @param aPrepareNextRequest True if this is when updating the image request.
+   * @param aFrame If called from FrameCreated the frame passed to FrameCreated.
+   *               This is our frame, but at the time of the FrameCreated call
+   *               our primary frame pointer hasn't been set yet, so this is
+   *               only way to get our frame.
+   */
+  void MaybeForceSyncDecoding(bool aPrepareNextRequest,
+                              nsIFrame* aFrame = nullptr);
+
+  /**
    * Typically we will have only one observer (our frame in the screen
    * prescontext), so we want to only make space for one and to
    * heap-allocate anything past that (saves memory and malloc churn
    * in the common case).  The storage is a linked list, we just
    * happen to actually hold the first observer instead of a pointer
    * to it.
    */
   ImageObserver mObserverList;
@@ -517,11 +545,14 @@ private:
   //
   // This member is used in SetBlockedRequest, if it's true, then this call is
   // triggered from LoadImage.
   // If this is false, it means this call is from other places like
   // ServiceWorker, then we will ignore call to SetBlockedRequest for now.
   //
   // Also we use this variable to check if some evil code is reentering LoadImage.
   bool mIsStartingImageLoad;
+
+  // If true, force frames to synchronously decode images on draw.
+  bool mSyncDecodingHint;
 };
 
 #endif // nsImageLoadingContent_h__
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -468,92 +468,91 @@ nsJSUtils::ExecutionContext::ExtractRetu
   return NS_OK;
 }
 
 nsresult
 nsJSUtils::CompileModule(JSContext* aCx,
                        JS::SourceBufferHolder& aSrcBuf,
                        JS::Handle<JSObject*> aEvaluationGlobal,
                        JS::CompileOptions &aCompileOptions,
-                       JS::MutableHandle<JSObject*> aModule)
+                       JS::MutableHandle<JSScript*> aScript)
 {
   AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS);
 
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(aSrcBuf.get());
   MOZ_ASSERT(JS_IsGlobalObject(aEvaluationGlobal));
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
 
   NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
 
-  if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
+  if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aScript)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsJSUtils::InitModuleSourceElement(JSContext* aCx,
-                                   JS::Handle<JSObject*> aModule,
+                                   JS::Handle<JSScript*> aScript,
                                    nsIScriptElement* aElement)
 {
   JS::Rooted<JS::Value> value(aCx);
   nsresult rv = nsContentUtils::WrapNative(aCx, aElement, &value,
                                            /* aAllowWrapping = */ true);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   MOZ_ASSERT(value.isObject());
   JS::Rooted<JSObject*> object(aCx, &value.toObject());
 
-  JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aModule));
-  if (!JS::InitScriptSourceElement(aCx, script, object, nullptr)) {
+  if (!JS::InitScriptSourceElement(aCx, aScript, object, nullptr)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule)
+nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSScript*> aScript)
 {
   AUTO_PROFILER_LABEL("nsJSUtils::ModuleInstantiate", JS);
 
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
 
-  NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aScript).Allowed(), NS_OK);
 
-  if (!JS::ModuleInstantiate(aCx, aModule)) {
+  if (!JS::ModuleInstantiate(aCx, aScript)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule)
+nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSScript*> aScript)
 {
   AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluate", JS);
 
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
 
-  NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aScript).Allowed(), NS_OK);
 
-  if (!JS::ModuleEvaluate(aCx, aModule)) {
+  if (!JS::ModuleEvaluate(aCx, aScript)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 static bool
 AddScopeChainItem(JSContext* aCx,
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -184,27 +184,27 @@ public:
                                  const uint8_t* aBuf, size_t aLength,
                                  JS::MutableHandle<JSScript*> aScript);
   };
 
   static nsresult CompileModule(JSContext* aCx,
                                 JS::SourceBufferHolder& aSrcBuf,
                                 JS::Handle<JSObject*> aEvaluationGlobal,
                                 JS::CompileOptions &aCompileOptions,
-                                JS::MutableHandle<JSObject*> aModule);
+                                JS::MutableHandle<JSScript*> aScript);
 
   static nsresult InitModuleSourceElement(JSContext* aCx,
-                                          JS::Handle<JSObject*> aModule,
+                                          JS::Handle<JSScript*> aScript,
                                           nsIScriptElement* aElement);
 
   static nsresult ModuleInstantiate(JSContext* aCx,
-                                    JS::Handle<JSObject*> aModule);
+                                    JS::Handle<JSScript*> aScript);
 
   static nsresult ModuleEvaluate(JSContext* aCx,
-                                 JS::Handle<JSObject*> aModule);
+                                 JS::Handle<JSScript*> aScript);
 
   // Returns false if an exception got thrown on aCx.  Passing a null
   // aElement is allowed; that wil produce an empty aScopeChain.
   static bool GetScopeChainForElement(JSContext* aCx,
                                       mozilla::dom::Element* aElement,
                                       JS::AutoObjectVector& aScopeChain);
 
   // Returns a scope chain suitable for XBL execution.
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1716,17 +1716,19 @@ inline JSObject*
 FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
 {
   if (!p) {
     return JS::CurrentGlobalOrNull(cx);
   }
 
   JSObject* global = p->GetGlobalJSObject();
   if (!global) {
-    return nullptr;
+    // nsIGlobalObject doesn't have a JS object anymore,
+    // fallback to the current global.
+    return JS::CurrentGlobalOrNull(cx);
   }
 
   MOZ_ASSERT(JS_IsGlobalObject(global));
   // This object could be gray if the nsIGlobalObject is the only thing keeping
   // it alive.
   JS::ExposeObjectToActiveJS(global);
   return global;
 }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1855,17 +1855,16 @@ addExternalIface('nsIWebNavigation', nat
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
 addExternalIface('nsIWebBrowserPersistDocumentReceiver',
                  nativeType='nsIWebBrowserPersistDocumentReceiver',
                  headerFile='nsIWebBrowserPersistDocument.h',
                  notflattened=True)
 addExternalIface('nsIWebProgressListener', nativeType='nsIWebProgressListener',
                  notflattened=True)
-addExternalIface('nsIScriptableRegion', nativeType='nsIScriptableRegion', notflattened=True)
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('StackFrame', nativeType='nsIStackFrame',
                  headerFile='nsIException.h', notflattened=True)
 addExternalIface('TabParent', nativeType='nsITabParent',
                  notflattened=True)
--- a/dom/encoding/TextDecoder.cpp
+++ b/dom/encoding/TextDecoder.cpp
@@ -10,44 +10,48 @@
 #include "mozilla/UniquePtrExtensions.h"
 #include "nsContentUtils.h"
 #include <stdint.h>
 
 namespace mozilla {
 namespace dom {
 
 void
-TextDecoder::Init(const nsAString& aLabel, const bool aFatal,
+TextDecoder::Init(const nsAString& aLabel,
+                  const TextDecoderOptions& aOptions,
                   ErrorResult& aRv)
 {
   // Let encoding be the result of getting an encoding from label.
   // If encoding is failure or replacement, throw a RangeError
   // (https://encoding.spec.whatwg.org/#dom-textdecoder).
   const Encoding* encoding = Encoding::ForLabelNoReplacement(aLabel);
   if (!encoding) {
     nsAutoString label(aLabel);
     label.Trim(" \t\n\f\r");
     aRv.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(label);
     return;
   }
-  InitWithEncoding(WrapNotNull(encoding), aFatal);
+  InitWithEncoding(WrapNotNull(encoding), aOptions);
 }
 
 void
 TextDecoder::InitWithEncoding(NotNull<const Encoding*> aEncoding,
-                              const bool aFatal)
+                              const TextDecoderOptions& aOptions)
 {
   aEncoding->Name(mEncoding);
-  // If the constructor is called with an options argument,
-  // and the fatal property of the dictionary is set,
-  // set the internal fatal flag of the decoder object.
-  mFatal = aFatal;
+  // Store the flags passed via our options dictionary.
+  mFatal = aOptions.mFatal;
+  mIgnoreBOM = aOptions.mIgnoreBOM;
 
   // Create a decoder object for mEncoding.
-  mDecoder = aEncoding->NewDecoderWithBOMRemoval();
+  if (mIgnoreBOM) {
+    mDecoder = aEncoding->NewDecoderWithoutBOMHandling();
+  } else {
+    mDecoder = aEncoding->NewDecoderWithBOMRemoval();
+  }
 }
 
 void
 TextDecoder::Decode(Span<const uint8_t> aInput,
                     const bool aStream,
                     nsAString& aOutDecodedString,
                     ErrorResult& aRv)
 {
--- a/dom/encoding/TextDecoder.h
+++ b/dom/encoding/TextDecoder.h
@@ -28,25 +28,26 @@ public:
   // The WebIDL constructor.
   static TextDecoder*
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aEncoding,
               const TextDecoderOptions& aOptions,
               ErrorResult& aRv)
   {
     nsAutoPtr<TextDecoder> txtDecoder(new TextDecoder());
-    txtDecoder->Init(aEncoding, aOptions.mFatal, aRv);
+    txtDecoder->Init(aEncoding, aOptions, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
     return txtDecoder.forget();
   }
 
   TextDecoder()
     : mFatal(false)
+    , mIgnoreBOM(false)
   {
     MOZ_COUNT_CTOR(TextDecoder);
   }
 
   ~TextDecoder()
   {
     MOZ_COUNT_DTOR(TextDecoder);
   }
@@ -55,32 +56,31 @@ public:
   {
     return TextDecoder_Binding::Wrap(aCx, this, aGivenProto, aReflector);
   }
 
   /**
    * Validates provided label and throws an exception if invalid label.
    *
    * @param aLabel       The encoding label (case insensitive) provided.
-   * @param aFatal       indicates whether to throw an 'EncodingError'
-   *                     exception or not when decoding.
+   * @param aOptions     The TextDecoderOptions to use.
    * @return aRv         EncodingError exception else null.
    */
-  void Init(const nsAString& aLabel, const bool aFatal, ErrorResult& aRv);
+  void Init(const nsAString& aLabel, const TextDecoderOptions& aOptions,
+            ErrorResult& aRv);
 
   /**
    * Performs initialization with a Gecko-canonical encoding name (as opposed
    * to a label.)
    *
    * @param aEncoding    An Encoding object
-   * @param aFatal       indicates whether to throw an 'EncodingError'
-   *                     exception or not when decoding.
+   * @param aOptions     The TextDecoderOptions to use.
    */
   void InitWithEncoding(NotNull<const Encoding*> aEncoding,
-                        const bool aFatal);
+                        const TextDecoderOptions& aOptions);
 
   /**
    * Return the encoding name.
    *
    * @param aEncoding, current encoding.
    */
   void GetEncoding(nsAString& aEncoding);
 
@@ -109,18 +109,23 @@ public:
               const TextDecodeOptions& aOptions,
               nsAString& aOutDecodedString,
               ErrorResult& aRv);
 
   bool Fatal() const {
     return mFatal;
   }
 
+  bool IgnoreBOM() const {
+    return mIgnoreBOM;
+  }
+
 private:
   nsCString mEncoding;
   mozilla::UniquePtr<mozilla::Decoder> mDecoder;
   bool mFatal;
+  bool mIgnoreBOM;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_textdecoder_h_
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2134,39 +2134,19 @@ EventStateManager::DoDefaultDragStart(ns
   // other than a selection is being dragged.
   if (!dragImage && aSelection) {
     dragService->InvokeDragSessionWithSelection(aSelection,
                                                 aPrincipalURISpec,
                                                 transArray,
                                                 action, event, dataTransfer);
   }
   else {
-    // if dragging within a XUL tree and no custom drag image was
-    // set, the region argument to InvokeDragSessionWithImage needs
-    // to be set to the area encompassing the selected rows of the
-    // tree to ensure that the drag feedback gets clipped to those
-    // rows. For other content, region should be null.
-    nsCOMPtr<nsIScriptableRegion> region;
-#ifdef MOZ_XUL
-    if (dragTarget && !dragImage) {
-      if (dragTarget->NodeInfo()->Equals(nsGkAtoms::treechildren,
-                                         kNameSpaceID_XUL)) {
-        nsTreeBodyFrame* treeBody =
-          do_QueryFrame(dragTarget->GetPrimaryFrame());
-        if (treeBody) {
-          treeBody->GetSelectionRegion(getter_AddRefs(region));
-        }
-      }
-    }
-#endif
-
     dragService->InvokeDragSessionWithImage(dragTarget,
                                             aPrincipalURISpec, transArray,
-                                            region, action,
-                                            dragImage,
+                                            action, dragImage,
                                             imageX, imageY, event,
                                             dataTransfer);
   }
 
   return true;
 }
 
 nsresult
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -217,31 +217,41 @@ HTMLImageElement::X()
 }
 
 int32_t
 HTMLImageElement::Y()
 {
   return GetXY().y;
 }
 
+void
+HTMLImageElement::GetDecoding(nsAString& aValue)
+{
+  GetEnumAttr(nsGkAtoms::decoding, kDecodingTableDefault->tag, aValue);
+}
+
 bool
 HTMLImageElement::ParseAttribute(int32_t aNamespaceID,
                                  nsAtom* aAttribute,
                                  const nsAString& aValue,
                                  nsIPrincipal* aMaybeScriptedPrincipal,
                                  nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::align) {
       return ParseAlignValue(aValue, aResult);
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
       ParseCORSValue(aValue, aResult);
       return true;
     }
+    if (aAttribute == nsGkAtoms::decoding) {
+      return aResult.ParseEnumValue(aValue, kDecodingTable, false,
+                                    kDecodingTableDefault);
+    }
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
@@ -373,16 +383,22 @@ HTMLImageElement::AfterSetAttr(int32_t a
     PictureSourceSrcsetChanged(this, attrVal.String(), aNotify);
   } else if (aName == nsGkAtoms::sizes &&
              aNameSpaceID == kNameSpaceID_None) {
     // Mark channel as urgent-start before load image if the image load is
     // initaiated by a user interaction.
     mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
 
     PictureSourceSizesChanged(this, attrVal.String(), aNotify);
+  } else if (aName == nsGkAtoms::decoding &&
+             aNameSpaceID == kNameSpaceID_None) {
+    // Request sync or async image decoding.
+    SetSyncDecodingHint(aValue &&
+                        static_cast<ImageDecodingType>(aValue->GetEnumValue()) ==
+                          ImageDecodingType::Sync);
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
                                             aValue, aOldValue,
                                             aMaybeScriptedPrincipal,
                                             aNotify);
 }
 
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -227,16 +227,21 @@ public:
   void SetReferrerPolicy(const nsAString& aReferrer, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrer, aError);
   }
   void GetReferrerPolicy(nsAString& aReferrer)
   {
     GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer);
   }
+  void SetDecoding(const nsAString& aDecoding, ErrorResult& aError)
+  {
+    SetHTMLAttr(nsGkAtoms::decoding, aDecoding, aError);
+  }
+  void GetDecoding(nsAString& aValue);
 
   net::ReferrerPolicy
   GetImageReferrerPolicy() override
   {
     return GetReferrerPolicyAsEnum();
   }
 
   MOZ_CAN_RUN_SCRIPT int32_t X();
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -670,54 +670,60 @@ DeserializeStructuredCloneFiles(
           StructuredCloneFile* file = aFiles.AppendElement();
           MOZ_ASSERT(file);
 
           file->mType = StructuredCloneFile::eStructuredClone;
 
           break;
         }
 
-        case StructuredCloneFile::eWasmBytecode:
-        case StructuredCloneFile::eWasmCompiled: {
+        case StructuredCloneFile::eWasmBytecode: {
           if (aModuleSet) {
             MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::Tnull_t);
 
             StructuredCloneFile* file = aFiles.AppendElement();
             MOZ_ASSERT(file);
 
-            file->mType = serializedFile.type();
+            file->mType = StructuredCloneFile::eWasmBytecode;
 
             MOZ_ASSERT(moduleIndex < aModuleSet->Length());
             file->mWasmModule = aModuleSet->ElementAt(moduleIndex);
 
-            if (serializedFile.type() == StructuredCloneFile::eWasmCompiled) {
-              moduleIndex++;
-            }
+            moduleIndex++;
 
             break;
           }
 
           MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::TIPCBlob);
 
           const IPCBlob& ipcBlob = blobOrMutableFile.get_IPCBlob();
 
           RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(ipcBlob);
           MOZ_ASSERT(blobImpl);
 
           RefPtr<Blob> blob = Blob::Create(aDatabase->GetOwner(), blobImpl);
 
           StructuredCloneFile* file = aFiles.AppendElement();
           MOZ_ASSERT(file);
 
-          file->mType = serializedFile.type();
+          file->mType = StructuredCloneFile::eWasmBytecode;
           file->mBlob.swap(blob);
 
           break;
         }
 
+        case StructuredCloneFile::eWasmCompiled: {
+          StructuredCloneFile* file = aFiles.AppendElement();
+          MOZ_ASSERT(file);
+
+          file->mType = StructuredCloneFile::eWasmCompiled;
+
+          break;
+        }
+
         default:
           MOZ_CRASH("Should never get here!");
       }
     }
   }
 }
 
 void
@@ -1476,41 +1482,36 @@ DispatchFileHandleSuccessEvent(FileHandl
  ******************************************************************************/
 
 // CancelableRunnable is used to make workers happy.
 class BackgroundRequestChild::PreprocessHelper final
   : public CancelableRunnable
   , public nsIInputStreamCallback
   , public nsIFileMetadataCallback
 {
-  typedef std::pair<nsCOMPtr<nsIInputStream>,
-                    nsCOMPtr<nsIInputStream>> StreamPair;
-
   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
-  nsTArray<StreamPair> mStreamPairs;
+  nsTArray<nsCOMPtr<nsIInputStream>> mStreams;
   nsTArray<RefPtr<JS::WasmModule>> mModuleSet;
   BackgroundRequestChild* mActor;
 
-  // These 2 are populated when the processing of the stream pairs runs.
+  // This is populated when the processing of the stream runs.
   PRFileDesc* mCurrentBytecodeFileDesc;
-  PRFileDesc* mCurrentCompiledFileDesc;
 
   RefPtr<TaskQueue> mTaskQueue;
   nsCOMPtr<nsIEventTarget> mTaskQueueEventTarget;
 
   uint32_t mModuleSetIndex;
   nsresult mResultCode;
 
 public:
   PreprocessHelper(uint32_t aModuleSetIndex, BackgroundRequestChild* aActor)
     : CancelableRunnable("indexedDB::BackgroundRequestChild::PreprocessHelper")
     , mOwningEventTarget(aActor->GetActorEventTarget())
     , mActor(aActor)
     , mCurrentBytecodeFileDesc(nullptr)
-    , mCurrentCompiledFileDesc(nullptr)
     , mModuleSetIndex(aModuleSetIndex)
     , mResultCode(NS_OK)
   {
     AssertIsOnOwningThread();
     MOZ_ASSERT(aActor);
     aActor->AssertIsOnOwningThread();
   }
 
@@ -1550,17 +1551,17 @@ private:
       mTaskQueue->BeginShutdown();
     }
   }
 
   void
   RunOnOwningThread();
 
   void
-  ProcessCurrentStreamPair();
+  ProcessCurrentStream();
 
   nsresult
   WaitForStreamReady(nsIInputStream* aInputStream);
 
   void
   ContinueWithStatus(nsresult aStatus);
 
   nsresult
@@ -3382,57 +3383,36 @@ BackgroundRequestChild::RecvPreprocess(c
 
 nsresult
 BackgroundRequestChild::
 PreprocessHelper::Init(const nsTArray<StructuredCloneFile>& aFiles)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!aFiles.IsEmpty());
 
-  uint32_t count = aFiles.Length();
-
-  // We should receive even number of files.
-  MOZ_ASSERT(count % 2 == 0);
-
-  // Let's process it as pairs.
-  count = count / 2;
-
-  nsTArray<StreamPair> streamPairs;
-  for (uint32_t index = 0; index < count; index++) {
-    uint32_t bytecodeIndex = index * 2;
-    uint32_t compiledIndex = bytecodeIndex + 1;
-
-    const StructuredCloneFile& bytecodeFile = aFiles[bytecodeIndex];
-    const StructuredCloneFile& compiledFile = aFiles[compiledIndex];
+  nsTArray<nsCOMPtr<nsIInputStream>> streams;
+  for (uint32_t index = 0; index < aFiles.Length(); index++) {
+    const StructuredCloneFile& bytecodeFile = aFiles[index];
 
     MOZ_ASSERT(bytecodeFile.mType == StructuredCloneFile::eWasmBytecode);
     MOZ_ASSERT(bytecodeFile.mBlob);
-    MOZ_ASSERT(compiledFile.mType == StructuredCloneFile::eWasmCompiled);
-    MOZ_ASSERT(compiledFile.mBlob);
 
     ErrorResult errorResult;
 
     nsCOMPtr<nsIInputStream> bytecodeStream;
     bytecodeFile.mBlob->CreateInputStream(getter_AddRefs(bytecodeStream),
                                           errorResult);
     if (NS_WARN_IF(errorResult.Failed())) {
       return errorResult.StealNSResult();
     }
 
-    nsCOMPtr<nsIInputStream> compiledStream;
-    compiledFile.mBlob->CreateInputStream(getter_AddRefs(compiledStream),
-                                          errorResult);
-    if (NS_WARN_IF(errorResult.Failed())) {
-      return errorResult.StealNSResult();
-    }
-
-    streamPairs.AppendElement(StreamPair(bytecodeStream, compiledStream));
+    streams.AppendElement(bytecodeStream);
   }
 
-  mStreamPairs = std::move(streamPairs);
+  mStreams = std::move(streams);
 
   return NS_OK;
 }
 
 nsresult
 BackgroundRequestChild::
 PreprocessHelper::Dispatch()
 {
@@ -3475,76 +3455,57 @@ PreprocessHelper::RunOnOwningThread()
     } else {
       mActor->OnPreprocessFailed(mModuleSetIndex, mResultCode);
     }
   }
 }
 
 void
 BackgroundRequestChild::
-PreprocessHelper::ProcessCurrentStreamPair()
+PreprocessHelper::ProcessCurrentStream()
 {
   MOZ_ASSERT(!IsOnOwningThread());
-  MOZ_ASSERT(!mStreamPairs.IsEmpty());
-
-  nsresult rv;
-
-  const StreamPair& streamPair = mStreamPairs[0];
+  MOZ_ASSERT(!mStreams.IsEmpty());
 
   // We still don't have the current bytecode FileDesc.
   if (!mCurrentBytecodeFileDesc) {
-    const nsCOMPtr<nsIInputStream>& bytecodeStream = streamPair.first;
+    const nsCOMPtr<nsIInputStream>& bytecodeStream = mStreams[0];
     MOZ_ASSERT(bytecodeStream);
 
     mCurrentBytecodeFileDesc = GetFileDescriptorFromStream(bytecodeStream);
     if (!mCurrentBytecodeFileDesc) {
-      rv = WaitForStreamReady(bytecodeStream);
+      nsresult rv = WaitForStreamReady(bytecodeStream);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         ContinueWithStatus(rv);
       }
       return;
     }
   }
 
-  if (!mCurrentCompiledFileDesc) {
-    const nsCOMPtr<nsIInputStream>& compiledStream = streamPair.second;
-    MOZ_ASSERT(compiledStream);
-
-    mCurrentCompiledFileDesc = GetFileDescriptorFromStream(compiledStream);
-    if (!mCurrentCompiledFileDesc) {
-      rv = WaitForStreamReady(compiledStream);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        ContinueWithStatus(rv);
-      }
-      return;
-    }
-  }
-
-  MOZ_ASSERT(mCurrentBytecodeFileDesc && mCurrentCompiledFileDesc);
+  MOZ_ASSERT(mCurrentBytecodeFileDesc);
 
   JS::BuildIdCharVector buildId;
   bool ok = GetBuildId(&buildId);
   if (NS_WARN_IF(!ok)) {
     ContinueWithStatus(NS_ERROR_FAILURE);
     return;
   }
 
   RefPtr<JS::WasmModule> module =
     JS::DeserializeWasmModule(mCurrentBytecodeFileDesc,
-                              mCurrentCompiledFileDesc,
                               std::move(buildId),
                               nullptr,
                               0);
   if (NS_WARN_IF(!module)) {
     ContinueWithStatus(NS_ERROR_FAILURE);
     return;
   }
 
   mModuleSet.AppendElement(module);
-  mStreamPairs.RemoveElementAt(0);
+  mStreams.RemoveElementAt(0);
 
   ContinueWithStatus(NS_OK);
 }
 
 nsresult
 BackgroundRequestChild::
 PreprocessHelper::WaitForStreamReady(nsIInputStream* aInputStream)
 {
@@ -3579,28 +3540,27 @@ PreprocessHelper::WaitForStreamReady(nsI
 void
 BackgroundRequestChild::
 PreprocessHelper::ContinueWithStatus(nsresult aStatus)
 {
   MOZ_ASSERT(!IsOnOwningThread());
 
   // Let's reset the value for the next operation.
   mCurrentBytecodeFileDesc = nullptr;
-  mCurrentCompiledFileDesc = nullptr;
 
   nsCOMPtr<nsIEventTarget> eventTarget;
 
   if (NS_WARN_IF(NS_FAILED(aStatus))) {
     // If the previous operation failed, we don't continue the processing of the
-    // other stream pairs.
+    // other streams.
     MOZ_ASSERT(mResultCode == NS_OK);
     mResultCode = aStatus;
 
     eventTarget = mOwningEventTarget;
-  } else if (mStreamPairs.IsEmpty()) {
+  } else if (mStreams.IsEmpty()) {
     // If all the streams have been processed, we can go back to the owning
     // thread.
     eventTarget = mOwningEventTarget;
   } else {
     // Continue the processing.
     eventTarget = mTaskQueueEventTarget;
   }
 
@@ -3614,17 +3574,17 @@ NS_IMPL_ISUPPORTS_INHERITED(BackgroundRe
 
 NS_IMETHODIMP
 BackgroundRequestChild::
 PreprocessHelper::Run()
 {
   if (IsOnOwningThread()) {
     RunOnOwningThread();
   } else {
-    ProcessCurrentStreamPair();
+    ProcessCurrentStream();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BackgroundRequestChild::
 PreprocessHelper::OnInputStreamReady(nsIAsyncInputStream* aStream)
@@ -3643,40 +3603,28 @@ PreprocessHelper::OnFileMetadataReady(ns
 }
 
 nsresult
 BackgroundRequestChild::
 PreprocessHelper::DataIsReady(nsIInputStream* aStream)
 {
   MOZ_ASSERT(!IsOnOwningThread());
   MOZ_ASSERT(aStream);
-  MOZ_ASSERT(!mStreamPairs.IsEmpty());
+  MOZ_ASSERT(!mStreams.IsEmpty());
 
   // We still don't have the current bytecode FileDesc.
   if (!mCurrentBytecodeFileDesc) {
     mCurrentBytecodeFileDesc = GetFileDescriptorFromStream(aStream);
     if (!mCurrentBytecodeFileDesc) {
       ContinueWithStatus(NS_ERROR_FAILURE);
       return NS_OK;
     }
 
-    // Let's continue with the processing of the current pair.
-    ProcessCurrentStreamPair();
-    return NS_OK;
-  }
-
-  if (!mCurrentCompiledFileDesc) {
-    mCurrentCompiledFileDesc = GetFileDescriptorFromStream(aStream);
-    if (!mCurrentCompiledFileDesc) {
-      ContinueWithStatus(NS_ERROR_FAILURE);
-      return NS_OK;
-    }
-
-    // Let's continue with the processing of the current pair.
-    ProcessCurrentStreamPair();
+    // Let's continue with the processing of the current stream.
+    ProcessCurrentStream();
     return NS_OK;
   }
 
   MOZ_CRASH("If we have both fileDescs why are we here?");
 }
 
 nsresult
 BackgroundRequestChild::
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -9629,39 +9629,28 @@ public:
 
   nsresult
   Init();
 
   already_AddRefed<nsIFile>
   GetFile(FileInfo* aFileInfo);
 
   already_AddRefed<nsIFile>
-  GetCheckedFile(FileInfo* aFileInfo);
-
-  already_AddRefed<nsIFile>
   GetJournalFile(FileInfo* aFileInfo);
 
   nsresult
   CreateFileFromStream(nsIFile* aFile,
                        nsIFile* aJournalFile,
                        nsIInputStream* aInputStream,
                        bool aCompress);
 
   nsresult
-  ReplaceFile(nsIFile* aFile,
-              nsIFile* aNewFile,
-              nsIFile* aNewJournalFile);
-
-  nsresult
   RemoveFile(nsIFile* aFile,
              nsIFile* aJournalFile);
 
-  already_AddRefed<FileInfo>
-  GetNewFileInfo();
-
 private:
   nsresult
   SyncCopy(nsIInputStream* aInputStream,
            nsIOutputStream* aOutputStream,
            char* aBuffer,
            uint32_t aBufferSize);
 
   nsresult
@@ -9731,159 +9720,28 @@ DeserializeStructuredCloneFile(FileManag
 
   aFile->mFileInfo.swap(fileInfo);
   aFile->mType = type;
 
   return NS_OK;
 }
 
 nsresult
-CheckWasmModule(FileHelper* aFileHelper,
-                StructuredCloneFile* aBytecodeFile,
-                StructuredCloneFile* aCompiledFile)
-{
-  MOZ_ASSERT(!IsOnBackgroundThread());
-  MOZ_ASSERT(aFileHelper);
-  MOZ_ASSERT(aBytecodeFile);
-  MOZ_ASSERT(aCompiledFile);
-  MOZ_ASSERT(aBytecodeFile->mType == StructuredCloneFile::eWasmBytecode);
-  MOZ_ASSERT(aCompiledFile->mType == StructuredCloneFile::eWasmCompiled);
-
-  nsCOMPtr<nsIFile> compiledFile =
-    aFileHelper->GetCheckedFile(aCompiledFile->mFileInfo);
-  if (NS_WARN_IF(!compiledFile)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsresult rv;
-
-  bool match;
-  {
-    ScopedPRFileDesc compiledFileDesc;
-    rv = compiledFile->OpenNSPRFileDesc(PR_RDONLY,
-                                        0644,
-                                        &compiledFileDesc.rwget());
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    JS::BuildIdCharVector buildId;
-    bool ok = GetBuildId(&buildId);
-    if (NS_WARN_IF(!ok)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    match = JS::CompiledWasmModuleAssumptionsMatch(compiledFileDesc,
-                                                   std::move(buildId));
-  }
-  if (match) {
-    return NS_OK;
-  }
-
-  // Re-compile the module.  It would be preferable to do this in the child
-  // (content process) instead of here in the parent, but that would be way more
-  // complex and without significant memory allocation or security benefits.
-  // See the discussion starting from
-  // https://bugzilla.mozilla.org/show_bug.cgi?id=1312808#c9 for more details.
-  nsCOMPtr<nsIFile> bytecodeFile =
-    aFileHelper->GetCheckedFile(aBytecodeFile->mFileInfo);
-  if (NS_WARN_IF(!bytecodeFile)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  ScopedPRFileDesc bytecodeFileDesc;
-  rv = bytecodeFile->OpenNSPRFileDesc(PR_RDONLY,
-                                      0644,
-                                      &bytecodeFileDesc.rwget());
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  JS::BuildIdCharVector buildId;
-  bool ok = GetBuildId(&buildId);
-  if (NS_WARN_IF(!ok)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  RefPtr<JS::WasmModule> module = JS::DeserializeWasmModule(bytecodeFileDesc,
-                                                            nullptr,
-                                                            std::move(buildId),
-                                                            nullptr,
-                                                            0);
-  if (NS_WARN_IF(!module)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  size_t compiledSize = module->compiledSerializedSize();
-  UniquePtr<uint8_t[]> compiled(new (fallible) uint8_t[compiledSize]);
-  if (NS_WARN_IF(!compiled)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  module->compiledSerialize(compiled.get(), compiledSize);
-
-  nsCOMPtr<nsIInputStream> inputStream;
-  rv = NS_NewByteInputStream(getter_AddRefs(inputStream),
-                             reinterpret_cast<const char*>(compiled.get()),
-                             compiledSize);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  RefPtr<FileInfo> newFileInfo = aFileHelper->GetNewFileInfo();
-
-  nsCOMPtr<nsIFile> newFile = aFileHelper->GetFile(newFileInfo);
-  if (NS_WARN_IF(!newFile)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIFile> newJournalFile =
-    aFileHelper->GetJournalFile(newFileInfo);
-  if (NS_WARN_IF(!newJournalFile)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  rv = aFileHelper->CreateFileFromStream(newFile,
-                                         newJournalFile,
-                                         inputStream,
-                                         /* aCompress */ false);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    nsresult rv2 = aFileHelper->RemoveFile(newFile, newJournalFile);
-    if (NS_WARN_IF(NS_FAILED(rv2))) {
-      return rv;
-    }
-    return rv;
-  }
-
-  rv = aFileHelper->ReplaceFile(compiledFile, newFile, newJournalFile);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    nsresult rv2 = aFileHelper->RemoveFile(newFile, newJournalFile);
-    if (NS_WARN_IF(NS_FAILED(rv2))) {
-      return rv;
-    }
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult
 DeserializeStructuredCloneFiles(FileManager* aFileManager,
                                 const nsAString& aText,
                                 nsTArray<StructuredCloneFile>& aResult,
                                 bool* aHasPreprocessInfo)
 {
   MOZ_ASSERT(!IsOnBackgroundThread());
 
   nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing>
     tokenizer(aText, ' ');
 
   nsAutoString token;
   nsresult rv;
-  Maybe<FileHelper> fileHelper;
 
   while (tokenizer.hasMoreTokens()) {
     token = tokenizer.nextToken();
     MOZ_ASSERT(!token.IsEmpty());
 
     StructuredCloneFile* file = aResult.AppendElement();
     rv = DeserializeStructuredCloneFile(aFileManager, token, file);
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -9893,36 +9751,20 @@ DeserializeStructuredCloneFiles(FileMana
     if (!aHasPreprocessInfo) {
       continue;
     }
 
     if (file->mType == StructuredCloneFile::eWasmBytecode) {
       *aHasPreprocessInfo = true;
     }
     else if (file->mType == StructuredCloneFile::eWasmCompiled) {
-      if (fileHelper.isNothing()) {
-        fileHelper.emplace(aFileManager);
-
-        rv = fileHelper->Init();
-        if (NS_WARN_IF(NS_FAILED(rv))) {
-          return rv;
-        }
-      }
-
       MOZ_ASSERT(aResult.Length() > 1);
       MOZ_ASSERT(aResult[aResult.Length() - 2].mType ==
                    StructuredCloneFile::eWasmBytecode);
 
-      StructuredCloneFile* previousFile = &aResult[aResult.Length() - 2];
-
-      rv = CheckWasmModule(fileHelper.ptr(), previousFile, file);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
-
       *aHasPreprocessInfo = true;
     }
   }
 
   return NS_OK;
 }
 
 bool
@@ -9973,19 +9815,17 @@ SerializeStructuredCloneFiles(
 
   if (NS_WARN_IF(!aResult.SetCapacity(count, fallible))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (uint32_t index = 0; index < count; index++) {
     const StructuredCloneFile& file = aFiles[index];
 
-    if (aForPreprocess &&
-        file.mType != StructuredCloneFile::eWasmBytecode &&
-        file.mType != StructuredCloneFile::eWasmCompiled) {
+    if (aForPreprocess && file.mType != StructuredCloneFile::eWasmBytecode) {
       continue;
     }
 
     const int64_t fileId = file.mFileInfo->Id();
     MOZ_ASSERT(fileId > 0);
 
     nsCOMPtr<nsIFile> nativeFile =
       mozilla::dom::indexedDB::FileManager::GetCheckedFileForId(directory, fileId);
@@ -10059,25 +9899,24 @@ SerializeStructuredCloneFiles(
         MOZ_ASSERT(file);
 
         file->file() = null_t();
         file->type() = StructuredCloneFile::eStructuredClone;
 
         break;
       }
 
-      case StructuredCloneFile::eWasmBytecode:
-      case StructuredCloneFile::eWasmCompiled: {
+      case StructuredCloneFile::eWasmBytecode: {
         if (!aForPreprocess) {
           SerializedStructuredCloneFile* serializedFile =
             aResult.AppendElement(fallible);
           MOZ_ASSERT(serializedFile);
 
           serializedFile->file() = null_t();
-          serializedFile->type() = file.mType;
+          serializedFile->type() = StructuredCloneFile::eWasmBytecode;
         } else {
           RefPtr<FileBlobImpl> impl = new FileBlobImpl(nativeFile);
           impl->SetFileId(file.mFileInfo->Id());
 
           IPCBlob ipcBlob;
           nsresult rv =
             IPCBlobUtils::Serialize(impl, aBackgroundActor, ipcBlob);
           if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -10086,24 +9925,34 @@ SerializeStructuredCloneFiles(
             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           }
 
           SerializedStructuredCloneFile* serializedFile =
             aResult.AppendElement(fallible);
           MOZ_ASSERT(serializedFile);
 
           serializedFile->file() = ipcBlob;
-          serializedFile->type() = file.mType;
+          serializedFile->type() = StructuredCloneFile::eWasmBytecode;
 
           aDatabase->MapBlob(ipcBlob, file.mFileInfo);
         }
 
         break;
       }
 
+      case StructuredCloneFile::eWasmCompiled: {
+        SerializedStructuredCloneFile* serializedFile =
+          aResult.AppendElement(fallible);
+        MOZ_ASSERT(serializedFile);
+
+        serializedFile->file() = null_t();
+        serializedFile->type() = StructuredCloneFile::eWasmCompiled;
+        break;
+      }
+
       default:
         MOZ_CRASH("Should never get here!");
     }
   }
 
   return NS_OK;
 }
 
@@ -29133,32 +28982,16 @@ FileHelper::GetFile(FileInfo* aFileInfo)
   MOZ_ASSERT(fileId > 0);
 
   nsCOMPtr<nsIFile> file =
     mFileManager->GetFileForId(mFileDirectory, fileId);
   return file.forget();
 }
 
 already_AddRefed<nsIFile>
-FileHelper::GetCheckedFile(FileInfo* aFileInfo)
-{
-  MOZ_ASSERT(!IsOnBackgroundThread());
-  MOZ_ASSERT(aFileInfo);
-  MOZ_ASSERT(mFileManager);
-  MOZ_ASSERT(mFileDirectory);
-
-  const int64_t fileId = aFileInfo->Id();
-  MOZ_ASSERT(fileId > 0);
-
-  nsCOMPtr<nsIFile> file =
-    mFileManager->GetCheckedFileForId(mFileDirectory, fileId);
-  return file.forget();
-}
-
-already_AddRefed<nsIFile>
 FileHelper::GetJournalFile(FileInfo* aFileInfo)
 {
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aFileInfo);
   MOZ_ASSERT(mFileManager);
   MOZ_ASSERT(mJournalDirectory);
 
   const int64_t fileId = aFileInfo->Id();
@@ -29275,69 +29108,16 @@ FileHelper::CreateFileFromStream(nsIFile
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult
-FileHelper::ReplaceFile(nsIFile* aFile,
-                        nsIFile* aNewFile,
-                        nsIFile* aNewJournalFile)
-{
-  MOZ_ASSERT(!IsOnBackgroundThread());
-  MOZ_ASSERT(aFile);
-  MOZ_ASSERT(aNewFile);
-  MOZ_ASSERT(aNewJournalFile);
-  MOZ_ASSERT(mFileManager);
-  MOZ_ASSERT(mFileDirectory);
-  MOZ_ASSERT(mJournalDirectory);
-
-  nsresult rv;
-
-  int64_t fileSize;
-
-  if (mFileManager->EnforcingQuota()) {
-    rv = aFile->GetFileSize(&fileSize);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
-  nsAutoString fileName;
-  rv = aFile->GetLeafName(fileName);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = aNewFile->RenameTo(nullptr, fileName);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  if (mFileManager->EnforcingQuota()) {
-    QuotaManager* quotaManager = QuotaManager::Get();
-    MOZ_ASSERT(quotaManager);
-
-    quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
-                                         mFileManager->Group(),
-                                         mFileManager->Origin(),
-                                         fileSize);
-  }
-
-  rv = aNewJournalFile->Remove(false);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult
 FileHelper::RemoveFile(nsIFile* aFile,
                        nsIFile* aJournalFile)
 {
   nsresult rv;
 
   int64_t fileSize;
 
   if (mFileManager->EnforcingQuota()) {
@@ -29365,24 +29145,16 @@ FileHelper::RemoveFile(nsIFile* aFile,
   rv = aJournalFile->Remove(false);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
-already_AddRefed<FileInfo>
-FileHelper::GetNewFileInfo()
-{
-  MOZ_ASSERT(mFileManager);
-
-  return mFileManager->GetNewFileInfo();
-}
-
 class FileHelper::ReadCallback final : public nsIInputStreamCallback
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   ReadCallback()
     : mMutex("ReadCallback::mMutex")
     , mCondVar(mMutex, "ReadCallback::mCondVar")
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -204,298 +204,16 @@ GenerateRequest(JSContext* aCx, IDBObjec
 
   RefPtr<IDBRequest> request =
     IDBRequest::Create(aCx, aObjectStore, transaction->Database(), transaction);
   MOZ_ASSERT(request);
 
   return request.forget();
 }
 
-// Blob internal code clones this stream before it's passed to IPC, so we
-// serialize module's optimized code only when AsyncWait() is called.
-class WasmCompiledModuleStream final
-  : public nsIAsyncInputStream
-  , public nsICloneableInputStream
-  , private JS::WasmModuleListener
-{
-  nsCOMPtr<nsISerialEventTarget> mOwningThread;
-
-  // Initially and while waiting for compilation to complete, the mModule field
-  // is non-null, keeping alive the module whose code needs to be serialized.
-  RefPtr<JS::WasmModule> mModule;
-
-  // A module stream can have up to one input stream callback.
-  nsCOMPtr<nsIInputStreamCallback> mCallback;
-
-  // When a module's optimized code is ready to be serialized, it will be
-  // serialized into mStream and the mModule will be released. At this point,
-  // stream reads will succeed.
-  nsCOMPtr<nsIInputStream> mStream;
-
-  // When the stream is finished reading or closed, mStatus will be changed from
-  // NS_OK to NS_BASE_STREAM_CLOSED or whatever status was passed to
-  // CloseWithStatus.
-  nsresult mStatus;
-
-public:
-  explicit WasmCompiledModuleStream(JS::WasmModule* aModule)
-    : mOwningThread(GetCurrentThreadSerialEventTarget())
-    , mModule(aModule)
-    , mStatus(NS_OK)
-  {
-    AssertIsOnOwningThread();
-    MOZ_ASSERT(aModule);
-  }
-
-  bool
-  IsOnOwningThread() const
-  {
-    MOZ_ASSERT(mOwningThread);
-
-    bool current;
-    return NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(&current)) && current;
-  }
-
-  void
-  AssertIsOnOwningThread() const
-  {
-    MOZ_ASSERT(IsOnOwningThread());
-  }
-
-private:
-  // Copy constructor for cloning.
-  explicit WasmCompiledModuleStream(const WasmCompiledModuleStream& aOther)
-    : mOwningThread(aOther.mOwningThread)
-    , mModule(aOther.mModule)
-    , mStatus(aOther.mStatus)
-  {
-    AssertIsOnOwningThread();
-
-    if (aOther.mStream) {
-      nsCOMPtr<nsICloneableInputStream> cloneableStream =
-        do_QueryInterface(aOther.mStream);
-      MOZ_ASSERT(cloneableStream);
-
-      MOZ_ALWAYS_SUCCEEDS(cloneableStream->Clone(getter_AddRefs(mStream)));
-    }
-  }
-
-  ~WasmCompiledModuleStream() override
-  {
-    AssertIsOnOwningThread();
-
-    MOZ_ALWAYS_SUCCEEDS(Close());
-  }
-
-  void
-  CallCallback()
-  {
-    AssertIsOnOwningThread();
-    MOZ_ASSERT(mCallback);
-
-    nsCOMPtr<nsIInputStreamCallback> callback;
-    callback.swap(mCallback);
-
-    callback->OnInputStreamReady(this);
-  }
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-
-  // nsIInputStream:
-
-  NS_IMETHOD
-  Close() override
-  {
-    AssertIsOnOwningThread();
-
-    return CloseWithStatus(NS_BASE_STREAM_CLOSED);
-  }
-
-  NS_IMETHOD
-  Available(uint64_t* _retval) override
-  {
-    AssertIsOnOwningThread();
-
-    if (NS_FAILED(mStatus)) {
-      return mStatus;
-    }
-
-    if (!mStream) {
-      *_retval = 0;
-      return NS_OK;
-    }
-
-    return mStream->Available(_retval);
-  }
-
-  NS_IMETHOD
-  Read(char* aBuf, uint32_t aCount, uint32_t* _retval) override
-  {
-    AssertIsOnOwningThread();
-
-    return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
-  }
-
-  NS_IMETHOD
-  ReadSegments(nsWriteSegmentFun aWriter,
-               void* aClosure,
-               uint32_t aCount,
-               uint32_t* _retval) override
-  {
-    AssertIsOnOwningThread();
-
-    if (NS_FAILED(mStatus)) {
-      *_retval = 0;
-      return NS_OK;
-    }
-
-    if (!mStream) {
-      return NS_BASE_STREAM_WOULD_BLOCK;
-    }
-
-    return mStream->ReadSegments(aWriter, aClosure, aCount, _retval);
-  }
-
-  NS_IMETHOD
-  IsNonBlocking(bool* _retval) override
-  {
-    AssertIsOnOwningThread();
-
-    *_retval = true;
-    return NS_OK;
-  }
-
-  // nsIAsyncInputStream:
-
-  NS_IMETHOD
-  CloseWithStatus(nsresult aStatus) override
-  {
-    AssertIsOnOwningThread();
-
-    if (NS_FAILED(mStatus)) {
-      return NS_OK;
-    }
-
-    mModule = nullptr;
-
-    if (mStream) {
-      MOZ_ALWAYS_SUCCEEDS(mStream->Close());
-      mStream = nullptr;
-    }
-
-    mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED;
-
-    if (mCallback) {
-      CallCallback();
-    }
-
-    return NS_OK;
-  }
-
-  NS_IMETHOD
-  AsyncWait(nsIInputStreamCallback* aCallback,
-            uint32_t aFlags,
-            uint32_t aRequestedCount,
-            nsIEventTarget* aEventTarget) override
-  {
-    AssertIsOnOwningThread();
-    MOZ_ASSERT_IF(mCallback, !aCallback);
-
-    if (aFlags) {
-      return NS_ERROR_NOT_IMPLEMENTED;
-    }
-
-    if (!aCallback) {
-      mCallback = nullptr;
-      return NS_OK;
-    }
-
-    if (aEventTarget) {
-      mCallback =
-        NS_NewInputStreamReadyEvent("WasmCompiledModuleStream::AsyncWait",
-                                    aCallback,
-                                    aEventTarget);
-    } else {
-      mCallback = aCallback;
-    }
-
-    if (NS_FAILED(mStatus) || mStream) {
-      CallCallback();
-      return NS_OK;
-    }
-
-    MOZ_ASSERT(mModule);
-    mModule->notifyWhenCompilationComplete(this);
-
-    return NS_OK;
-  }
-
-  // nsICloneableInputStream:
-
-  NS_IMETHOD
-  GetCloneable(bool* aCloneable) override
-  {
-    AssertIsOnOwningThread();
-
-    *aCloneable = true;
-    return NS_OK;
-  }
-
-  NS_IMETHOD
-  Clone(nsIInputStream** _retval) override
-  {
-    AssertIsOnOwningThread();
-
-    nsCOMPtr<nsIInputStream> clone = new WasmCompiledModuleStream(*this);
-
-    clone.forget(_retval);
-    return NS_OK;
-  }
-
-  // JS::WasmModuleListener:
-
-  void
-  onCompilationComplete() override
-  {
-    if (!IsOnOwningThread()) {
-      MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(NewCancelableRunnableMethod(
-        "WasmCompiledModuleStream::onCompilationComplete",
-        this,
-        &WasmCompiledModuleStream::onCompilationComplete)));
-      return;
-    }
-
-    if (NS_FAILED(mStatus) || !mCallback) {
-      return;
-    }
-
-    MOZ_ASSERT(mModule);
-
-    size_t compiledSize = mModule->compiledSerializedSize();
-
-    nsCString compiled;
-    compiled.SetLength(compiledSize);
-
-    mModule->compiledSerialize(
-      reinterpret_cast<uint8_t*>(compiled.BeginWriting()), compiledSize);
-
-    MOZ_ALWAYS_SUCCEEDS(NS_NewCStringInputStream(getter_AddRefs(mStream),
-                                                 std::move(compiled)));
-
-    mModule = nullptr;
-
-    CallCallback();
-  }
-};
-
-NS_IMPL_ISUPPORTS(WasmCompiledModuleStream,
-                  nsIInputStream,
-                  nsIAsyncInputStream,
-                  nsICloneableInputStream)
-
 bool
 StructuredCloneWriteCallback(JSContext* aCx,
                              JSStructuredCloneWriter* aWriter,
                              JS::Handle<JSObject*> aObj,
                              void* aClosure)
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aWriter);
@@ -642,71 +360,16 @@ StructuredCloneWriteCallback(JSContext* 
       StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
       newFile->mBlob = blob;
       newFile->mType = StructuredCloneFile::eBlob;
 
       return true;
     }
   }
 
-  if (JS::IsWasmModuleObject(aObj)) {
-    RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
-    MOZ_ASSERT(module);
-
-    size_t bytecodeSize = module->bytecodeSerializedSize();
-    UniquePtr<uint8_t[], JS::FreePolicy> bytecode(js_pod_malloc<uint8_t>(bytecodeSize));
-    module->bytecodeSerialize(bytecode.get(), bytecodeSize);
-
-    RefPtr<BlobImpl> blobImpl =
-      new MemoryBlobImpl(bytecode.release(), bytecodeSize, EmptyString());
-
-    RefPtr<Blob> bytecodeBlob = Blob::Create(nullptr, blobImpl);
-
-    if (module->compilationComplete()) {
-      size_t compiledSize = module->compiledSerializedSize();
-      UniquePtr<uint8_t[]> compiled(new uint8_t[compiledSize]);
-      module->compiledSerialize(compiled.get(), compiledSize);
-
-      blobImpl =
-        new MemoryBlobImpl(compiled.release(), compiledSize, EmptyString());
-    } else {
-      nsCOMPtr<nsIInputStream> stream(new WasmCompiledModuleStream(module));
-
-      blobImpl = StreamBlobImpl::Create(stream.forget(), EmptyString(),
-                                        UINT64_MAX);
-    }
-
-    RefPtr<Blob> compiledBlob = Blob::Create(nullptr, blobImpl);
-
-    if (cloneWriteInfo->mFiles.Length() + 1 > size_t(UINT32_MAX)) {
-      MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
-      return false;
-    }
-
-    const uint32_t index = cloneWriteInfo->mFiles.Length();
-
-    // The ordering of the bytecode and compiled file is significant and must
-    // never be changed. These two files must always form a pair
-    // [eWasmBytecode, eWasmCompiled]. Everything else depends on it!
-    if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, /* flags */ 0) ||
-        !JS_WriteUint32Pair(aWriter, index, index + 1)) {
-      return false;
-    }
-
-    StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
-    newFile->mBlob = bytecodeBlob;
-    newFile->mType = StructuredCloneFile::eWasmBytecode;
-
-    newFile = cloneWriteInfo->mFiles.AppendElement();
-    newFile->mBlob = compiledBlob;
-    newFile->mType = StructuredCloneFile::eWasmCompiled;
-
-    return true;
-  }
-
   return StructuredCloneHolder::WriteFullySerializableObjects(aCx, aWriter, aObj);
 }
 
 bool
 CopyingStructuredCloneWriteCallback(JSContext* aCx,
                                     JSStructuredCloneWriter* aWriter,
                                     JS::Handle<JSObject*> aObj,
                                     void* aClosure)
@@ -763,39 +426,16 @@ CopyingStructuredCloneWriteCallback(JSCo
       StructuredCloneFile* newFile = cloneInfo->mFiles.AppendElement();
       newFile->mMutableFile = mutableFile;
       newFile->mType = StructuredCloneFile::eMutableFile;
 
       return true;
     }
   }
 
-  if (JS::IsWasmModuleObject(aObj)) {
-    RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
-    MOZ_ASSERT(module);
-
-    if (cloneInfo->mFiles.Length() > size_t(UINT32_MAX)) {
-      MOZ_ASSERT(false,
-                 "Fix the structured clone data to use a bigger type!");
-      return false;
-    }
-
-    const uint32_t index = cloneInfo->mFiles.Length();
-
-    if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, index)) {
-      return false;
-    }
-
-    StructuredCloneFile* newFile = cloneInfo->mFiles.AppendElement();
-    newFile->mWasmModule = module;
-    newFile->mType = StructuredCloneFile::eWasmBytecode;
-
-    return true;
-  }
-
   return StructuredCloneHolder::WriteFullySerializableObjects(aCx, aWriter, aObj);
 }
 
 nsresult
 GetAddInfoCallback(JSContext* aCx, void* aClosure)
 {
   static const JSStructuredCloneCallbacks kStructuredCloneCallbacks = {
     nullptr /* read */,
@@ -1111,17 +751,17 @@ public:
 
   static bool
   CreateAndWrapWasmModule(JSContext* aCx,
                           StructuredCloneFile& aFile,
                           const WasmModuleData& aData,
                           JS::MutableHandle<JSObject*> aResult)
   {
     MOZ_ASSERT(aCx);
-    MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmCompiled);
+    MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmBytecode);
     MOZ_ASSERT(!aFile.mBlob);
 
     // If we don't have a WasmModule, we are probably using it for an index
     // creation, but Wasm module can't be used in index creation, so just make a
     // dummy object.
     if (!aFile.mWasmModule) {
       JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
 
@@ -1179,17 +819,17 @@ CommonStructuredCloneReadCallback(JSCont
       MOZ_ASSERT(!data.flags);
 
       if (data.bytecodeIndex >= cloneReadInfo->mFiles.Length() ||
           data.compiledIndex >= cloneReadInfo->mFiles.Length()) {
         MOZ_ASSERT(false, "Bad index value!");
         return nullptr;
       }
 
-      StructuredCloneFile& file = cloneReadInfo->mFiles[data.compiledIndex];
+      StructuredCloneFile& file = cloneReadInfo->mFiles[data.bytecodeIndex];
 
       if (NS_WARN_IF(!ValueDeserializationHelper::CreateAndWrapWasmModule(aCx,
                                                                           file,
                                                                           data,
                                                                           &result))) {
         return nullptr;
       }
 
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -109,22 +109,17 @@ support-files =
   unit/test_transaction_duplicate_store_names.js
   unit/test_transaction_error.js
   unit/test_transaction_lifetimes.js
   unit/test_transaction_lifetimes_nested.js
   unit/test_transaction_ordering.js
   unit/test_upgrade_add_index.js
   unit/test_unique_index_update.js
   unit/test_view_put_get_values.js
-  unit/test_wasm_cursors.js
-  unit/test_wasm_getAll.js
-  unit/test_wasm_index_getAllObjects.js
-  unit/test_wasm_indexes.js
   unit/test_wasm_put_get_values.js
-  unit/test_wasm_serialize_tiering.js
   unit/test_writer_starvation.js
 
 [test_abort_deleted_index.html]
 [test_abort_deleted_objectStore.html]
 [test_add_put.html]
 [test_add_twice_failure.html]
 [test_advance.html]
 [test_autoIncrement.html]
@@ -266,14 +261,9 @@ scheme=https
 [test_transaction_duplicate_store_names.html]
 [test_transaction_error.html]
 [test_transaction_lifetimes.html]
 [test_transaction_lifetimes_nested.html]
 [test_transaction_ordering.html]
 [test_unique_index_update.html]
 [test_upgrade_add_index.html]
 [test_view_put_get_values.html]
-[test_wasm_cursors.html]
-[test_wasm_getAll.html]
-[test_wasm_index_getAllObjects.html]
-[test_wasm_indexes.html]
 [test_wasm_put_get_values.html]
-[test_wasm_serialize_tiering.html]
deleted file mode 100644
--- a/dom/indexedDB/test/test_wasm_cursors.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript" src="unit/test_wasm_cursors.js"></script>
-  <script type="text/javascript" src="file.js"></script>
-  <script type="text/javascript" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
deleted file mode 100644
--- a/dom/indexedDB/test/test_wasm_getAll.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript" src="unit/test_wasm_getAll.js"></script>
-  <script type="text/javascript" src="file.js"></script>
-  <script type="text/javascript" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
deleted file mode 100644
--- a/dom/indexedDB/test/test_wasm_index_getAllObjects.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript" src="unit/test_wasm_index_getAllObjects.js"></script>
-  <script type="text/javascript" src="file.js"></script>
-  <script type="text/javascript" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
deleted file mode 100644
--- a/dom/indexedDB/test/test_wasm_indexes.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript" src="unit/test_wasm_indexes.js"></script>
-  <script type="text/javascript" src="file.js"></script>
-  <script type="text/javascript" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
deleted file mode 100644
--- a/dom/indexedDB/test/test_wasm_serialize_tiering.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript" src="unit/test_wasm_serialize_tiering.js"></script>
-  <script type="text/javascript" src="file.js"></script>
-  <script type="text/javascript" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
--- a/dom/indexedDB/test/unit/test_upgrade_add_index.js
+++ b/dom/indexedDB/test/unit/test_upgrade_add_index.js
@@ -49,29 +49,16 @@ function* testSteps()
       id: 1,
       what: "crypto",
       data: key
     });
   } else {
     info("not storing crypto key");
   }
 
-  if (isWasmSupported()) {
-    info("creating wasm");
-    getWasmBinary("(module (func (nop)))");
-    let binary = yield undefined;
-    allData.push({
-      id: 2,
-      what: "wasm",
-      data: getWasmModule(binary)
-    });
-  } else {
-    info("not storing wasm");
-  }
-
   // -- Create the IDB and populate it with the base data.
   info("opening initial database");
   let request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler; // advance onupgradeneeded
   let event = yield undefined; // wait for onupgradeneeded.
 
   let db = event.target.result;
deleted file mode 100644
--- a/dom/indexedDB/test/unit/test_wasm_cursors.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-var testGenerator = testSteps();
-
-function* testSteps()
-{
-  const name =
-    this.window ? window.location.pathname : "test_wasm_cursors.js";
-
-  const objectStoreName = "Wasm";
-
-  const wasmData = { key: 1, value: null };
-
-  if (!isWasmSupported()) {
-    finishTest();
-    return;
-  }
-
-  getWasmBinary("(module (func (nop)))");
-  let binary = yield undefined;
-  wasmData.value = getWasmModule(binary);
-
-  info("Opening database");
-
-  let request = indexedDB.open(name);
-  request.onerror = errorHandler;
-  request.onupgradeneeded = continueToNextStepSync;
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  // upgradeneeded
-  request.onupgradeneeded = unexpectedSuccessHandler;
-  request.onsuccess = continueToNextStepSync;
-
-  info("Creating objectStore");
-
-  request.result.createObjectStore(objectStoreName);
-
-  yield undefined;
-
-  // success
-  let db = request.result;
-  db.onerror = errorHandler;
-
-  info("Storing wasm");
-
-  let objectStore = db.transaction([objectStoreName], "readwrite")
-                      .objectStore(objectStoreName);
-  request = objectStore.add(wasmData.value, wasmData.key);
-  request.onsuccess = continueToNextStepSync;
-  yield undefined;
-
-  is(request.result, wasmData.key, "Got correct key");
-
-  info("Opening cursor");
-
-  request = objectStore.openCursor();
-  request.addEventListener("error", new ExpectError("UnknownError", true));
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  finishTest();
-}
deleted file mode 100644
--- a/dom/indexedDB/test/unit/test_wasm_getAll.js
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-var testGenerator = testSteps();
-
-function* testSteps()
-{
-  const name =
-    this.window ? window.location.pathname : "test_wasm_getAll.js";
-
-  const objectStoreName = "Wasm";
-
-  const wasmData = [
-    { key: 1, value: 42 },
-    { key: 2, value: [null, null, null] },
-    { key: 3, value: [null, null, null, null, null] }
-  ];
-
-  if (!isWasmSupported()) {
-    finishTest();
-    return;
-  }
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 1)))`);
-  let binary = yield undefined;
-  wasmData[1].value[0] = getWasmModule(binary);
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 2)))`);
-  binary = yield undefined;
-  wasmData[1].value[1] = getWasmModule(binary);
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 3)))`);
-  binary = yield undefined;
-  wasmData[1].value[2] = getWasmModule(binary);
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 4)))`);
-  binary = yield undefined;
-  wasmData[2].value[0] = getWasmModule(binary);
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 5)))`);
-  binary = yield undefined;
-  wasmData[2].value[1] = getWasmModule(binary);
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 6)))`);
-  binary = yield undefined;
-  wasmData[2].value[2] = getWasmModule(binary);
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 7)))`);
-  binary = yield undefined;
-  wasmData[2].value[3] = getWasmModule(binary);
-
-  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 8)))`);
-  binary = yield undefined;
-  wasmData[2].value[4] = getWasmModule(binary);
-
-  let request = indexedDB.open(name, 1);
-  request.onerror = errorHandler;
-  request.onupgradeneeded = continueToNextStepSync;
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  // upgradeneeded
-  request.onupgradeneeded = unexpectedSuccessHandler;
-  request.onsuccess = continueToNextStepSync;
-
-  info("Creating objectStore");
-
-  request.result.createObjectStore(objectStoreName);
-
-  yield undefined;
-
-  // success
-  let db = request.result;
-  db.onerror = errorHandler;
-
-  info("Storing values");
-
-  let objectStore = db.transaction([objectStoreName], "readwrite")
-                      .objectStore(objectStoreName);
-  let addedCount = 0;
-  for (let i in wasmData) {
-    request = objectStore.add(wasmData[i].value, wasmData[i].key);
-    request.onsuccess = function(event) {
-      if (++addedCount == wasmData.length) {
-        continueToNextStep();
-      }
-    };
-  }
-  yield undefined;
-
-  info("Getting values");
-
-  request = db.transaction(objectStoreName)
-              .objectStore(objectStoreName)
-              .getAll();
-  request.onsuccess = continueToNextStepSync;
-  yield undefined;
-
-  info("Verifying values");
-
-  // Can't call yield inside of the verify function.
-  let modulesToProcess = [];
-
-  function verifyArray(array1, array2) {
-    is(array1 instanceof Array, true, "Got an array object");
-    is(array1.length, array2.length, "Same length");
-  }
-
-  function verifyData(data1, data2) {
-    if (data2 instanceof Array) {
-      verifyArray(data1, data2);
-      for (let i in data2) {
-        verifyData(data1[i], data2[i]);
-      }
-    } else if (data2 instanceof WebAssembly.Module) {
-      modulesToProcess.push({ module1: data1, module2: data2 });
-    } else {
-      is(data1, data2, "Same value");
-    }
-  }
-
-  verifyArray(request.result, wasmData);
-  for (let i in wasmData) {
-    verifyData(request.result[i], wasmData[i].value);
-  }
-
-  for (let moduleToProcess of modulesToProcess) {
-    verifyWasmModule(moduleToProcess.module1, moduleToProcess.module2);
-    yield undefined;
-  }
-
-  finishTest();
-}
deleted file mode 100644
--- a/dom/indexedDB/test/unit/test_wasm_index_getAllObjects.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-var testGenerator = testSteps();
-
-function* testSteps()
-{
-  const name =
-    this.window ? window.location.pathname : "test_wasm_getAll.js";
-
-  const objectStoreName = "Wasm";
-
-  const wasmData = [
-    { key: 1, value: { name: "foo1", data: 42 } },
-    { key: 2, value: { name: "foo2", data: [null, null, null] } },
-    { key: 3, value: { name: "foo3", data: [null, null, null, null, null] } }
-  ];
-
-  const indexData = { name: "nameIndex", keyPath: "name", options: { } };
-
-  if (!isWasmSupported()) {
-    finishTest();
-    return;
-  }
-
-  getWasmBinary("(module (func (result i32) (i32.const 1)))");
-  let binary = yield undefined;
-  wasmData[1].value.data[0] = getWasmModule(binary);
-
-  getWasmBinary("(module (func (result i32) (i32.const 2)))");
-  binary = yield undefined;
-  wasmData[1].value.data[1] = getWasmModule(binary);
-
-  getWasmBinary("(module (func (result i32) (i32.const 3)))");
-  binary = yield undefined;
-  wasmData[1].value.data[2] = getWasmModule(binary);
-
-  getWasmBinary("(module (func (result i32) (i32.const 4)))");
-  binary = yield undefined;
-  wasmData[2].value.data[0] = getWasmModule(binary);
-
-  getWasmBinary("(module (func (result i32) (i32.const 5)))");
-  binary = yield undefined;
-  wasmData[2].value.data[1] = getWasmModule(binary);
-
-  getWasmBinary("(module (func (result i32) (i32.const 6)))");
-  binary = yield undefined;
-  wasmData[2].value.data[2] = getWasmModule(binary);
-
-  getWasmBinary("(module (func (result i32) (i32.const 7)))");
-  binary = yield undefined;
-  wasmData[2].value.data[3] = getWasmModule(binary);
-
-  getWasmBinary("(module (func (result i32) (i32.const 8)))");
-  binary = yield undefined;
-  wasmData[2].value.data[4] = getWasmModule(binary);
-
-  let request = indexedDB.open(name, 1);
-  request.onerror = errorHandler;
-  request.onupgradeneeded = continueToNextStepSync;
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  // upgradeneeded
-  request.onupgradeneeded = unexpectedSuccessHandler;
-  request.onsuccess = continueToNextStepSync;
-
-  info("Creating objectStore");
-
-  let objectStore = request.result.createObjectStore(objectStoreName);
-
-  info("Creating index");
-
-  objectStore.createIndex(indexData.name, indexData.keyPath, indexData.options);
-
-  yield undefined;
-
-  // success
-  let db = request.result;
-  db.onerror = errorHandler;
-
-  info("Storing values");
-
-  objectStore = db.transaction([objectStoreName], "readwrite")
-                  .objectStore(objectStoreName);
-  let addedCount = 0;
-  for (let i in wasmData) {
-    request = objectStore.add(wasmData[i].value, wasmData[i].key);
-    request.onsuccess = function(event) {
-      if (++addedCount == wasmData.length) {
-        continueToNextStep();
-      }
-    };
-  }
-  yield undefined;
-
-  info("Getting values");
-
-  request = db.transaction(objectStoreName)
-              .objectStore(objectStoreName)
-              .index("nameIndex")
-              .getAll();
-  request.addEventListener("error", new ExpectError("UnknownError", true));
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  finishTest();
-}
deleted file mode 100644
--- a/dom/indexedDB/test/unit/test_wasm_indexes.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-var testGenerator = testSteps();
-
-function* testSteps()
-{
-  const name =
-    this.window ? window.location.pathname : "test_wasm_indexes.js";
-
-  const objectStoreName = "Wasm";
-
-  const wasmData = { key: 1, value: { name: "foo", data: null } };
-
-  const indexData = { name: "nameIndex", keyPath: "name", options: { } };
-
-  if (!isWasmSupported()) {
-    finishTest();
-    return;
-  }
-
-  getWasmBinary("(module (func (nop)))");
-  let binary = yield undefined;
-  wasmData.value.data = getWasmModule(binary);
-
-  info("Opening database");
-
-  let request = indexedDB.open(name);
-  request.onerror = errorHandler;
-  request.onupgradeneeded = continueToNextStepSync;
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  // upgradeneeded
-  request.onupgradeneeded = unexpectedSuccessHandler;
-  request.onsuccess = continueToNextStepSync;
-
-  info("Creating objectStore");
-
-  let objectStore = request.result.createObjectStore(objectStoreName);
-
-  info("Creating index");
-
-  objectStore.createIndex(indexData.name, indexData.keyPath, indexData.options);
-
-  yield undefined;
-
-  // success
-  let db = request.result;
-  db.onerror = errorHandler;
-
-  info("Storing wasm");
-
-  objectStore = db.transaction([objectStoreName], "readwrite")
-                  .objectStore(objectStoreName);
-  request = objectStore.add(wasmData.value, wasmData.key);
-  request.onsuccess = continueToNextStepSync;
-  yield undefined;
-
-  is(request.result, wasmData.key, "Got correct key");
-
-  info("Getting wasm");
-
-  request = objectStore.index("nameIndex").get("foo");
-  request.addEventListener("error", new ExpectError("UnknownError", true));
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  info("Opening cursor");
-
-  request = objectStore.index("nameIndex").openCursor();
-  request.addEventListener("error", new ExpectError("UnknownError", true));
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  finishTest();
-}
--- a/dom/indexedDB/test/unit/test_wasm_put_get_values.js
+++ b/dom/indexedDB/test/unit/test_wasm_put_get_values.js
@@ -40,43 +40,26 @@ function* testSteps()
   request.result.createObjectStore(objectStoreName);
 
   yield undefined;
 
   // success
   let db = request.result;
   db.onerror = errorHandler;
 
-  info("Storing wasm");
+  info("Testing failure to store wasm");
 
   let objectStore = db.transaction([objectStoreName], "readwrite")
                       .objectStore(objectStoreName);
-  request = objectStore.add(wasmData.value, wasmData.key);
-  request.onsuccess = continueToNextStepSync;
-  yield undefined;
 
-  is(request.result, wasmData.key, "Got correct key");
-
-  info("Getting wasm");
-
-  request = objectStore.get(wasmData.key);
-  request.onsuccess = continueToNextStepSync;
-  yield undefined;
-
-  info("Verifying wasm");
-
-  verifyWasmModule(request.result, wasmData.value);
-  yield undefined;
-
-  info("Getting wasm in new transaction");
-
-  request = db.transaction([objectStoreName])
-              .objectStore(objectStoreName).get(wasmData.key);
-  request.onsuccess = continueToNextStepSync;
-  yield undefined;
-
-  info("Verifying wasm");
-
-  verifyWasmModule(request.result, wasmData.value);
-  yield undefined;
+  // storing a wasm module in IDB should now fail
+  let failed = false;
+  try {
+    objectStore.add(wasmData.value, wasmData.key);
+  } catch (err) {
+    failed = true;
+    ok(err instanceof DOMException, "caught right error type");
+    is(err.name, "DataCloneError", "caught right error name");
+  }
+  ok(failed, "error was thrown");
 
   finishTest();
 }
--- a/dom/indexedDB/test/unit/test_wasm_recompile.js
+++ b/dom/indexedDB/test/unit/test_wasm_recompile.js
@@ -89,19 +89,19 @@ function* testSteps()
   fileReader = new FileReader();
   fileReader.onload = continueToNextStepSync;
   fileReader.readAsArrayBuffer(domFile);
 
   yield undefined;
 
   let newCompiledBuffer = fileReader.result;
 
-  info("Verifying blobs differ");
+  info("Verifying that re-storing of re-compiled code has been disabled");
 
-  ok(!compareBuffers(newCompiledBuffer, compiledBuffer), "Blobs differ");
+  ok(compareBuffers(newCompiledBuffer, compiledBuffer), "Blobs don't differ");
 
   info("Getting wasm again");
 
   request = db.transaction([objectStoreName])
               .objectStore(objectStoreName).get(wasmData.key);
   request.onsuccess = continueToNextStepSync;
   yield undefined;
 
deleted file mode 100644
--- a/dom/indexedDB/test/unit/test_wasm_serialize_tiering.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-var testGenerator = testSteps();
-
-function* testSteps()
-{
-  const name =
-    this.window ? window.location.pathname : "test_wasm_serialize_tiering.js";
-
-  const objectStoreName = "Wasm";
-
-  if (!isWasmSupported()) {
-    finishTest();
-    return;
-  }
-
-  // Make a module big enough so that tiering is significant.
-  const N = 50;
-  let bigFunc = `(func (result f64)\n`;
-  for (let i = 0; i < N; i++) {
-    bigFunc += `  f64.const 1.0\n`;
-  }
-  for (let i = 0; i < N - 1; i++) {
-    bigFunc += `  f64.add\n`;
-  }
-  bigFunc += `)`;
-  let bigModule = `(module \n`;
-  for (let i = 0; i < 100; i++) {
-    bigModule += bigFunc;
-  }
-  bigModule += `  (export "run" (func 10))\n`;
-  bigModule += `)`;
-
-  getWasmBinary(bigModule);
-  let bigBinary = yield undefined;
-
-  info("Opening database");
-
-  let request = indexedDB.open(name);
-  request.onerror = errorHandler;
-  request.onupgradeneeded = continueToNextStepSync;
-  request.onsuccess = unexpectedSuccessHandler;
-  yield undefined;
-
-  // upgradeneeded
-  request.onupgradeneeded = unexpectedSuccessHandler;
-  request.onsuccess = continueToNextStepSync;
-
-  info("Creating objectStore");
-
-  request.result.createObjectStore(objectStoreName);
-
-  yield undefined;
-
-  // success
-  let db = request.result;
-  db.onerror = errorHandler;
-
-  info("Storing wasm modules");
-
-  let objectStore = db.transaction([objectStoreName], "readwrite")
-                      .objectStore(objectStoreName);
-
-  const NumModules = 5;
-  const NumCopies = 5;
-
-  let finishedAdds = 0;
-  for (let moduleIndex = 0; moduleIndex < NumModules; moduleIndex++) {
-    let module = new WebAssembly.Module(bigBinary);
-    for (let copyIndex = 0; copyIndex < NumCopies; copyIndex++) {
-      let key = String(moduleIndex) + " " + String(copyIndex);
-      let request = objectStore.add(module, key);
-      request.onsuccess = function() {
-        is(request.result, key, "Got correct key");
-        if (++finishedAdds === NumModules * NumCopies) {
-          continueToNextStepSync();
-        }
-      };
-    }
-  }
-  yield undefined;
-
-  info("Getting wasm");
-
-  let finishedGets = 0;
-  for (let moduleIndex = 0; moduleIndex < NumModules; moduleIndex++) {
-    for (let copyIndex = 0; copyIndex < NumCopies; copyIndex++) {
-      let key = String(moduleIndex) + " " + String(copyIndex);
-      let request = objectStore.get(key);
-      request.onsuccess = function() {
-        let module = request.result;
-        let instance = new WebAssembly.Instance(module);
-        is(instance.exports.run(), N, "Got correct run() result");
-        if (++finishedGets === NumModules * NumCopies) {
-          continueToNextStepSync();
-        }
-      };
-    }
-  }
-  yield undefined;
-
-  finishTest();
-}
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -641,12 +641,8 @@ var SpecialPowers = {
         try {
           testFile.remove(false);
         } catch (e) {}
       });
       this._createdFiles = null;
     }
   },
 };
-
-// This can be removed soon when on by default.
-if (SpecialPowers.isMainProcess())
-  SpecialPowers.setBoolPref("javascript.options.wasm_baselinejit", true);
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -61,20 +61,11 @@ skip-if = true
 [test_schema23upgrade.js]
 [test_snappyUpgrade.js]
 [test_storageOption_pref.js]
 skip-if = os == "android"
 [test_storagePersistentUpgrade.js]
 [test_temporary_storage.js]
 # bug 951017: intermittent failure on Android x86 emulator
 skip-if = os == "android" && processor == "x86"
-[test_view_put_get_values.js]
-[test_wasm_cursors.js]
-[test_wasm_getAll.js]
-skip-if = coverage # bug 1336727
-[test_wasm_index_getAllObjects.js]
-[test_wasm_indexes.js]
 [test_wasm_put_get_values.js]
-skip-if = coverage # bug 1336727
 [test_wasm_recompile.js]
 skip-if = coverage # bug 1336727
-[test_wasm_serialize_tiering.js]
-skip-if = coverage # bug 1336727
--- a/dom/plugins/ipc/hangui/moz.build
+++ b/dom/plugins/ipc/hangui/moz.build
@@ -21,12 +21,11 @@ if CONFIG['CC_TYPE'] in ('clang', 'gcc')
     WIN32_EXE_LDFLAGS += ['-municode']
 
 RCINCLUDE = 'HangUIDlg.rc'
 
 OS_LIBS += [
     'comctl32',
 ]
 
-if ((CONFIG['MOZ_PGO'] or
-     (not CONFIG['HAVE_64BIT_BUILD'] and CONFIG['ENABLE_CLANG_PLUGIN']))
+if (not CONFIG['HAVE_64BIT_BUILD'] and CONFIG['ENABLE_CLANG_PLUGIN']
     and CONFIG['CC_TYPE'] == 'clang-cl'):
     AllowCompilerWarnings()  # workaround for bug 1090497
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -5356,20 +5356,16 @@ QuotaManager::EnsureOriginIsInitializedI
       *aCreated = false;
       return NS_OK;
     }
   } else {
     rv = EnsureTemporaryStorageIsInitialized();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
-
-    mTemporaryStorageInitialized = true;
-
-    CheckTemporaryStorageLimits();
   }
 
   bool created;
   rv = EnsureOriginDirectory(directory, &created);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
--- a/dom/script/ModuleScript.cpp
+++ b/dom/script/ModuleScript.cpp
@@ -16,108 +16,108 @@ namespace dom {
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
-  tmp->UnlinkModuleRecord();
+  tmp->UnlinkScript();
   tmp->mParseError.setUndefined();
   tmp->mErrorToRethrow.setUndefined();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScript)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
 
 ModuleScript::ModuleScript(ScriptLoader* aLoader, nsIURI* aBaseURL)
  : mLoader(aLoader),
    mBaseURL(aBaseURL),
    mSourceElementAssociated(false)
 {
   MOZ_ASSERT(mLoader);
   MOZ_ASSERT(mBaseURL);
-  MOZ_ASSERT(!mModuleRecord);
+  MOZ_ASSERT(!mScript);
   MOZ_ASSERT(!HasParseError());
   MOZ_ASSERT(!HasErrorToRethrow());
 }
 
 void
-ModuleScript::UnlinkModuleRecord()
+ModuleScript::UnlinkScript()
 {
   // Remove module's back reference to this object request if present.
-  if (mModuleRecord) {
-    MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
+  if (mScript) {
+    MOZ_ASSERT(JS::GetModuleHostDefinedField(mScript).toPrivate() ==
                this);
-    JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
-    mModuleRecord = nullptr;
+    JS::SetModuleHostDefinedField(mScript, JS::UndefinedValue());
+    mScript = nullptr;
   }
 }
 
 ModuleScript::~ModuleScript()
 {
   // The object may be destroyed without being unlinked first.
-  UnlinkModuleRecord();
+  UnlinkScript();
   DropJSObjects(this);
 }
 
 void
-ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
+ModuleScript::SetScript(JS::Handle<JSScript*> aScript)
 {
-  MOZ_ASSERT(!mModuleRecord);
+  MOZ_ASSERT(!mScript);
   MOZ_ASSERT(!HasParseError());
   MOZ_ASSERT(!HasErrorToRethrow());
 
-  mModuleRecord = aModuleRecord;
+  mScript = aScript;
 
   // Make module's host defined field point to this module script object.
-  // This is cleared in the UnlinkModuleRecord().
-  JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this));
+  // This is cleared in the UnlinkScript().
+  JS::SetModuleHostDefinedField(mScript, JS::PrivateValue(this));
   HoldJSObjects(this);
 }
 
 void
 ModuleScript::SetParseError(const JS::Value& aError)
 {
   MOZ_ASSERT(!aError.isUndefined());
   MOZ_ASSERT(!HasParseError());
   MOZ_ASSERT(!HasErrorToRethrow());
 
-  UnlinkModuleRecord();
+  UnlinkScript();
   mParseError = aError;
   HoldJSObjects(this);
 }
 
 void
 ModuleScript::SetErrorToRethrow(const JS::Value& aError)
 {
   MOZ_ASSERT(!aError.isUndefined());
   MOZ_ASSERT(!HasErrorToRethrow());
 
-  // This is only called after SetModuleRecord() or SetParseError() so we don't
+  // This is only called after SetScript() or SetParseError() so we don't
   // need to call HoldJSObjects() here.
-  MOZ_ASSERT(mModuleRecord || HasParseError());
+  MOZ_ASSERT(mScript || HasParseError());
 
   mErrorToRethrow = aError;
 }
 
 void
 ModuleScript::SetSourceElementAssociated()
 {
-  MOZ_ASSERT(mModuleRecord);
+  MOZ_ASSERT(mScript);
   MOZ_ASSERT(!mSourceElementAssociated);
 
   mSourceElementAssociated = true;
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/script/ModuleScript.h
+++ b/dom/script/ModuleScript.h
@@ -17,43 +17,43 @@ namespace mozilla {
 namespace dom {
 
 class ScriptLoader;
 
 class ModuleScript final : public nsISupports
 {
   RefPtr<ScriptLoader> mLoader;
   nsCOMPtr<nsIURI> mBaseURL;
-  JS::Heap<JSObject*> mModuleRecord;
+  JS::Heap<JSScript*> mScript;
   JS::Heap<JS::Value> mParseError;
   JS::Heap<JS::Value> mErrorToRethrow;
   bool mSourceElementAssociated;
 
   ~ModuleScript();
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
 
   ModuleScript(ScriptLoader* aLoader,
                nsIURI* aBaseURL);
 
-  void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
+  void SetScript(JS::Handle<JSScript*> aScript);
   void SetParseError(const JS::Value& aError);
   void SetErrorToRethrow(const JS::Value& aError);
   void SetSourceElementAssociated();
 
   ScriptLoader* Loader() const { return mLoader; }
-  JSObject* ModuleRecord() const { return mModuleRecord; }
+  JSScript* Script() const { return mScript; }
   nsIURI* BaseURL() const { return mBaseURL; }
   JS::Value ParseError() const { return mParseError; }
   JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
   bool HasParseError() const { return !mParseError.isUndefined(); }
   bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
   bool SourceElementAssociated() const { return mSourceElementAssociated; }
 
-  void UnlinkModuleRecord();
+  void UnlinkScript();
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_ModuleScript_h
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -473,56 +473,60 @@ ScriptLoader::CreateModuleScript(ModuleL
   AutoEntryScript aes(globalObject, "CompileModule", true);
 
   bool oldProcessingScriptTag = context->GetProcessingScriptTag();
   context->SetProcessingScriptTag(true);
 
   nsresult rv;
   {
     JSContext* cx = aes.cx();
-    JS::Rooted<JSObject*> module(cx);
+    JS::Rooted<JSScript*> script(cx);
 
     if (aRequest->mWasCompiledOMT) {
-      module = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
+      script = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
       aRequest->mOffThreadToken = nullptr;
-      rv = module ? NS_OK : NS_ERROR_FAILURE;
+      rv = script ? NS_OK : NS_ERROR_FAILURE;
     } else {
       JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
 
       JS::CompileOptions options(cx);
       rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
 
       if (NS_SUCCEEDED(rv)) {
-        SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
-        rv = nsJSUtils::CompileModule(cx, srcBuf, global, options, &module);
+        auto srcBuf = GetScriptSource(cx, aRequest);
+        if (srcBuf) {
+          rv = nsJSUtils::CompileModule(cx, *srcBuf, global, options, &script);
+        } else {
+          rv = NS_ERROR_OUT_OF_MEMORY;
+        }
       }
     }
 
-    MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
+    MOZ_ASSERT(NS_SUCCEEDED(rv) == (script != nullptr));
 
     RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL);
     aRequest->mModuleScript = moduleScript;
 
-    if (!module) {
+    if (!script) {
       LOG(("ScriptLoadRequest (%p):   compilation failed (%d)",
            aRequest, unsigned(rv)));
 
       MOZ_ASSERT(aes.HasException());
       JS::Rooted<JS::Value> error(cx);
       if (!aes.StealException(&error)) {
         aRequest->mModuleScript = nullptr;
         return NS_ERROR_FAILURE;
       }
 
       moduleScript->SetParseError(error);
       aRequest->ModuleErrored();
       return NS_OK;
     }
 
-    moduleScript->SetModuleRecord(module);
+    moduleScript->SetScript(script);
 
     // Validate requested modules and treat failure to resolve module specifiers
     // the same as a parse error.
     rv = ResolveRequestedModules(aRequest, nullptr);
     if (NS_FAILED(rv)) {
       aRequest->ModuleErrored();
       return NS_OK;
     }
@@ -605,24 +609,24 @@ ResolveModuleSpecifier(ModuleScript* aSc
 }
 
 static nsresult
 ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOut)
 {
   ModuleScript* ms = aRequest->mModuleScript;
 
   AutoJSAPI jsapi;
-  if (!jsapi.Init(ms->ModuleRecord())) {
+  if (!jsapi.Init(JS::GetScriptGlobal(ms->Script()))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
-  JS::Rooted<JSObject*> moduleRecord(cx, ms->ModuleRecord());
+  JS::Rooted<JSScript*> script(cx, ms->Script());
   JS::Rooted<JSObject*> requestedModules(cx);
-  requestedModules = JS::GetRequestedModules(cx, moduleRecord);
+  requestedModules = JS::GetRequestedModules(cx, script);
   MOZ_ASSERT(requestedModules);
 
   uint32_t length;
   if (!JS_GetArrayLength(cx, requestedModules, &length)) {
     return NS_ERROR_FAILURE;
   }
 
   JS::Rooted<JS::Value> element(cx);
@@ -746,24 +750,24 @@ ScriptLoader::StartFetchingModuleAndDepe
     childRequest->mReady.Reject(rv, __func__);
     return ready;
   }
 
   return ready;
 }
 
 // 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
-JSObject*
-HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
+JSScript*
+HostResolveImportedModule(JSContext* aCx, JS::Handle<JSScript*> aScript,
                           JS::Handle<JSString*> aSpecifier)
 {
   // Let referencing module script be referencingModule.[[HostDefined]].
-  JS::Value value = JS::GetModuleHostDefinedField(aModule);
+  JS::Value value = JS::GetModuleHostDefinedField(aScript);
   auto script = static_cast<ModuleScript*>(value.toPrivate());
-  MOZ_ASSERT(script->ModuleRecord() == aModule);
+  MOZ_ASSERT(script->Script() == aScript);
 
   // Let url be the result of resolving a module specifier given referencing
   // module script and specifier.
   nsAutoJSString string;
   if (!string.init(aCx, aSpecifier)) {
     return nullptr;
   }
 
@@ -774,35 +778,35 @@ HostResolveImportedModule(JSContext* aCx
   MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier");
 
   // Let resolved module script be moduleMap[url]. (This entry must exist for us
   // to have gotten to this point.)
   ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
   MOZ_ASSERT(ms, "Resolved module not found in module map");
 
   MOZ_ASSERT(!ms->HasParseError());
-  MOZ_ASSERT(ms->ModuleRecord());
-
-  return ms->ModuleRecord();
+  MOZ_ASSERT(ms->Script());
+
+  return ms->Script();
 }
 
 bool
-HostPopulateImportMeta(JSContext* aCx, JS::Handle<JSObject*> aModule,
+HostPopulateImportMeta(JSContext* aCx, JS::Handle<JSScript*> aScript,
                        JS::Handle<JSObject*> aMetaObject)
 {
-  MOZ_DIAGNOSTIC_ASSERT(aModule);
-
-  JS::Value value = JS::GetModuleHostDefinedField(aModule);
+  MOZ_DIAGNOSTIC_ASSERT(aScript);
+
+  JS::Value value = JS::GetModuleHostDefinedField(aScript);
   if (value.isUndefined()) {
     JS_ReportErrorASCII(aCx, "Module script not found");
     return false;
   }
 
   auto script = static_cast<ModuleScript*>(value.toPrivate());
-  MOZ_DIAGNOSTIC_ASSERT(script->ModuleRecord() == aModule);
+  MOZ_DIAGNOSTIC_ASSERT(script->Script() == aScript);
 
   nsAutoCString url;
   MOZ_DIAGNOSTIC_ASSERT(script->BaseURL());
   MOZ_ALWAYS_SUCCEEDS(script->BaseURL()->GetAsciiSpec(url));
 
   JS::Rooted<JSString*> urlString(aCx, JS_NewStringCopyZ(aCx, url.get()));
   if (!urlString) {
     JS_ReportOutOfMemory(aCx);
@@ -923,28 +927,28 @@ ScriptLoader::InstantiateModuleTree(Modu
 
   JS::Value parseError = FindFirstParseError(aRequest);
   if (!parseError.isUndefined()) {
     moduleScript->SetErrorToRethrow(parseError);
     LOG(("ScriptLoadRequest (%p):   found parse error", aRequest));
     return true;
   }
 
-  MOZ_ASSERT(moduleScript->ModuleRecord());
+  MOZ_ASSERT(moduleScript->Script());
 
   nsAutoMicroTask mt;
   AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) {
+  if (NS_WARN_IF(!jsapi.Init(JS::GetScriptGlobal(moduleScript->Script())))) {
     return false;
   }
 
   EnsureModuleResolveHook(jsapi.cx());
 
-  JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
-  bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
+  JS::Rooted<JSScript*> script(jsapi.cx(), moduleScript->Script());
+  bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), script));
 
   if (!ok) {
     LOG(("ScriptLoadRequest (%p): Instantiate failed", aRequest));
     MOZ_ASSERT(jsapi.HasException());
     JS::RootedValue exception(jsapi.cx());
     if (!jsapi.StealException(&exception)) {
       return false;
     }
@@ -1819,21 +1823,21 @@ ScriptLoader::AttemptAsyncScriptCompile(
     }
   }
 
   RefPtr<NotifyOffThreadScriptLoadCompletedRunnable> runnable =
     new NotifyOffThreadScriptLoadCompletedRunnable(aRequest, this);
 
   if (aRequest->IsModuleRequest()) {
     MOZ_ASSERT(aRequest->IsTextSource());
-    SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
-    if (!JS::CompileOffThreadModule(cx, options,
-                                    srcBuf,
-                                    OffThreadScriptLoaderCallback,
-                                    static_cast<void*>(runnable))) {
+    auto srcBuf = GetScriptSource(cx, aRequest);
+    if (!srcBuf || !JS::CompileOffThreadModule(cx, options,
+                                               *srcBuf,
+                                               OffThreadScriptLoaderCallback,
+                                               static_cast<void*>(runnable))) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   } else if (aRequest->IsBytecode()) {
     if (!JS::DecodeOffThreadScript(cx, options,
                                    aRequest->mScriptBytecode,
                                    aRequest->mBytecodeOffset,
                                    OffThreadScriptLoaderCallback,
                                    static_cast<void*>(runnable))) {
@@ -1847,21 +1851,21 @@ ScriptLoader::AttemptAsyncScriptCompile(
                                    aRequest->ScriptBinASTData().length(),
                                    OffThreadScriptLoaderCallback,
                                    static_cast<void*>(runnable))) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 #endif
   } else {
     MOZ_ASSERT(aRequest->IsTextSource());
-    SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
-    if (!JS::CompileOffThread(cx, options,
-                              srcBuf,
-                              OffThreadScriptLoaderCallback,
-                              static_cast<void*>(runnable))) {
+    auto srcBuf = GetScriptSource(cx, aRequest);
+    if (!srcBuf || !JS::CompileOffThread(cx, options,
+                                         *srcBuf,
+                                         OffThreadScriptLoaderCallback,
+                                         static_cast<void*>(runnable))) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   mDocument->BlockOnload();
 
   // Once the compilation is finished, an event would be added to the event loop
   // to call ScriptLoader::ProcessOffThreadRequest with the same request.
@@ -1891,38 +1895,40 @@ ScriptLoader::CompileOffThreadOrProcessR
 
   if (couldCompile) {
     return NS_OK;
   }
 
   return ProcessRequest(aRequest);
 }
 
-SourceBufferHolder
+mozilla::Maybe<SourceBufferHolder>
 ScriptLoader::GetScriptSource(JSContext* aCx, ScriptLoadRequest* aRequest)
 {
   // Return a SourceBufferHolder object holding the script's source text.
   // Ownership of the buffer is transferred to the resulting SourceBufferHolder.
 
   // If there's no script text, we try to get it from the element
   if (aRequest->mIsInline) {
     nsAutoString inlineData;
     aRequest->Element()->GetScriptText(inlineData);
 
     size_t nbytes = inlineData.Length() * sizeof(char16_t);
     JS::UniqueTwoByteChars chars(static_cast<char16_t*>(JS_malloc(aCx, nbytes)));
-    MOZ_RELEASE_ASSERT(chars);
+    if (!chars) {
+      return Nothing();
+    }
+
     memcpy(chars.get(), inlineData.get(), nbytes);
-    return SourceBufferHolder(std::move(chars), inlineData.Length());
+    return Some(SourceBufferHolder(std::move(chars), inlineData.Length()));
   }
 
   size_t length = aRequest->ScriptText().length();
-  return SourceBufferHolder(aRequest->ScriptText().extractOrCopyRawBuffer(),
-                            length,
-                            SourceBufferHolder::GiveOwnership);
+  JS::UniqueTwoByteChars chars(aRequest->ScriptText().extractOrCopyRawBuffer());
+  return Some(SourceBufferHolder(std::move(chars), length));
 }
 
 nsresult
 ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
 {
   LOG(("ScriptLoadRequest (%p): Process request", aRequest));
 
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
@@ -2292,30 +2298,29 @@ ScriptLoader::EvaluateScript(ScriptLoadR
       ModuleScript* moduleScript = request->mModuleScript;
       if (moduleScript->HasErrorToRethrow()) {
         LOG(("ScriptLoadRequest (%p):   module has error to rethrow", aRequest));
         JS::Rooted<JS::Value> error(cx, moduleScript->ErrorToRethrow());
         JS_SetPendingException(cx, error);
         return NS_OK; // An error is reported by AutoEntryScript.
       }
 
-      JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
-      MOZ_ASSERT(module);
+      JS::Rooted<JSScript*> script(cx, moduleScript->Script());
+      MOZ_ASSERT(script);
 
       if (!moduleScript->SourceElementAssociated()) {
-        rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->Element());
+        rv = nsJSUtils::InitModuleSourceElement(cx, script, aRequest->Element());
         NS_ENSURE_SUCCESS(rv, rv);
         moduleScript->SetSourceElementAssociated();
 
         // The script is now ready to be exposed to the debugger.
-        JS::Rooted<JSScript*> script(cx, JS::GetModuleScript(module));
         JS::ExposeScriptToDebugger(cx, script);
       }
 
-      rv = nsJSUtils::ModuleEvaluate(cx, module);
+      rv = nsJSUtils::ModuleEvaluate(cx, script);
       MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
       if (NS_FAILED(rv)) {
         LOG(("ScriptLoadRequest (%p):   evaluation failed", aRequest));
         rv = NS_OK; // An error is reported by AutoEntryScript.
       }
 
       aRequest->mCacheInfo = nullptr;
     } else {
@@ -2364,24 +2369,27 @@ ScriptLoader::EvaluateScript(ScriptLoadR
               LOG(("ScriptLoadRequest (%p): Compile And Exec", aRequest));
               if (aRequest->IsBinASTSource()) {
                 rv = exec.DecodeBinASTAndExec(options,
                                               aRequest->ScriptBinASTData().begin(),
                                               aRequest->ScriptBinASTData().length(),
                                               &script);
               } else {
                 MOZ_ASSERT(aRequest->IsTextSource());
-                SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
-
-                if (recordreplay::IsRecordingOrReplaying()) {
-                  recordreplay::NoteContentParse(this, options.filename(), "application/javascript",
-                                                 srcBuf.get(), srcBuf.length());
+                auto srcBuf = GetScriptSource(cx, aRequest);
+
+                if (srcBuf) {
+                  if (recordreplay::IsRecordingOrReplaying()) {
+                    recordreplay::NoteContentParse(this, options.filename(), "application/javascript",
+                                                   srcBuf->get(), srcBuf->length());
+                  }
+                  rv = exec.CompileAndExec(options, *srcBuf, &script);
+                } else {
+                  rv = NS_ERROR_OUT_OF_MEMORY;
                 }
-
-                rv = exec.CompileAndExec(options, srcBuf, &script);
               }
             }
           }
 
           // Queue the current script load request to later save the bytecode.
           if (script && encodeBytecode) {
             aRequest->mScript = script;
             HoldJSObjects(aRequest);
--- a/dom/script/ScriptLoader.h
+++ b/dom/script/ScriptLoader.h
@@ -19,16 +19,17 @@
 #include "nsIDocument.h"
 #include "nsIIncrementalStreamLoader.h"
 #include "nsURIHashKey.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ScriptLoadRequest.h"
 #include "mozilla/dom/SRIMetadata.h"
 #include "mozilla/dom/SRICheck.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "mozilla/Vector.h"
 
 class nsIURI;
 
 namespace JS {
   class SourceBufferHolder;
@@ -501,31 +502,31 @@ private:
                                 nsresult aStatus);
 
   void AddDeferRequest(ScriptLoadRequest* aRequest);
   void AddAsyncRequest(ScriptLoadRequest* aRequest);
   bool MaybeRemovedDeferRequests();
 
   void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
 
-  JS::SourceBufferHolder GetScriptSource(JSContext* aCx,
-                                         ScriptLoadRequest* aRequest);
+  mozilla::Maybe<JS::SourceBufferHolder> GetScriptSource(JSContext* aCx,
+                                                         ScriptLoadRequest* aRequest);
 
   void SetModuleFetchStarted(ModuleLoadRequest *aRequest);
   void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest* aRequest,
                                                       nsresult aResult);
 
   bool IsFetchingModule(ModuleLoadRequest* aRequest) const;
 
   bool ModuleMapContainsURL(nsIURI* aURL) const;
   RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsIURI* aURL);
   ModuleScript* GetFetchedModule(nsIURI* aURL) const;
 
-  friend JSObject*
-  HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
+  friend JSScript*
+  HostResolveImportedModule(JSContext* aCx, JS::Handle<JSScript*> aScript,
                           JS::Handle<JSString*> aSpecifier);
 
   // Returns wether we should save the bytecode of this script after the
   // execution of the script.
   static bool
   ShouldCacheBytecode(ScriptLoadRequest* aRequest);
 
   nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
--- a/dom/svg/SVGImageElement.cpp
+++ b/dom/svg/SVGImageElement.cpp
@@ -109,16 +109,22 @@ SVGImageElement::PreserveAspectRatio()
 already_AddRefed<SVGAnimatedString>
 SVGImageElement::Href()
 {
   return mStringAttributes[HREF].IsExplicitlySet()
          ? mStringAttributes[HREF].ToDOMAnimatedString(this)
          : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
 }
 
+void
+SVGImageElement::GetDecoding(nsAString& aValue)
+{
+  GetEnumAttr(nsGkAtoms::decoding, kDecodingTableDefault->tag, aValue);
+}
+
 //----------------------------------------------------------------------
 
 nsresult
 SVGImageElement::LoadSVGImage(bool aForce, bool aNotify)
 {
   // resolve href attribute
   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
 
@@ -147,32 +153,56 @@ void
 SVGImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
 {
   nsImageLoadingContent::AsyncEventRunning(aEvent);
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods:
 
+bool
+SVGImageElement::ParseAttribute(int32_t aNamespaceID,
+                                 nsAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsIPrincipal* aMaybeScriptedPrincipal,
+                                 nsAttrValue& aResult)
+{
+  if (aNamespaceID == kNameSpaceID_None) {
+    if (aAttribute == nsGkAtoms::decoding) {
+      return aResult.ParseEnumValue(aValue, kDecodingTable, false,
+                                    kDecodingTableDefault);
+    }
+  }
+
+  return SVGImageElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
+                                             aMaybeScriptedPrincipal, aResult);
+}
+
 nsresult
 SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
                               const nsAttrValue* aValue,
                               const nsAttrValue* aOldValue,
                               nsIPrincipal* aSubjectPrincipal,
                               bool aNotify)
 {
   if (aName == nsGkAtoms::href &&
       (aNamespaceID == kNameSpaceID_None ||
        aNamespaceID == kNameSpaceID_XLink)) {
 
     if (aValue) {
       LoadSVGImage(true, aNotify);
     } else {
       CancelImageRequests(aNotify);
     }
+  } else if (aName == nsGkAtoms::decoding &&
+             aNamespaceID == kNameSpaceID_None) {
+    // Request sync or async image decoding.
+    SetSyncDecodingHint(aValue &&
+                        static_cast<ImageDecodingType>(aValue->GetEnumValue())
+                          == ImageDecodingType::Sync);
   }
   return SVGImageElementBase::AfterSetAttr(aNamespaceID, aName,
                                            aValue, aOldValue,
                                            aSubjectPrincipal, aNotify);
 }
 
 void
 SVGImageElement::MaybeLoadSVGImage()
--- a/dom/svg/SVGImageElement.h
+++ b/dom/svg/SVGImageElement.h
@@ -40,16 +40,21 @@ public:
   // interfaces:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // EventTarget
   virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
 
   // nsIContent interface
+  bool ParseAttribute(int32_t aNamespaceID,
+                      nsAtom* aAttribute,
+                      const nsAString& aValue,
+                      nsIPrincipal* aMaybeScriptedPrincipal,
+                      nsAttrValue& aResult) override;
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
                                 const nsAttrValue* aValue,
                                 const nsAttrValue* aOldValue,
                                 nsIPrincipal* aSubjectPrincipal,
                                 bool aNotify) override;
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
@@ -76,16 +81,22 @@ public:
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Height();
   already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
   already_AddRefed<SVGAnimatedString> Href();
 
+  void SetDecoding(const nsAString& aDecoding, ErrorResult& aError)
+  {
+    SetAttr(nsGkAtoms::decoding, aDecoding, aError);
+  }
+  void GetDecoding(nsAString& aValue);
+
 protected:
   nsresult LoadSVGImage(bool aForce, bool aNotify);
 
   virtual LengthAttributesInfo GetLengthInfo() override;
   virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override;
   virtual StringAttributesInfo GetStringInfo() override;
 
   // Override for nsImageLoadingContent.
--- a/dom/url/moz.build
+++ b/dom/url/moz.build
@@ -25,11 +25,8 @@ LOCAL_INCLUDES += [
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ]
 BROWSER_CHROME_MANIFESTS += [ 'tests/browser.ini' ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
-
-if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
-    AllowCompilerWarnings()  # workaround for bug 1090497
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -402,16 +402,21 @@ partial interface Document {
   [ChromeOnly] readonly attribute URI? mozDocumentURIIfNotForErrorPages;
 
   // A promise that is resolved, with this document itself, when we have both
   // fired DOMContentLoaded and are ready to start layout.  This is used for the
   // "document_idle" webextension script injection point.
   [ChromeOnly, Throws]
   readonly attribute Promise<Document> documentReadyForIdle;
 
+  // Lazily created command dispatcher, returns null if the document is not
+  // chrome privileged.
+  [ChromeOnly]
+  readonly attribute XULCommandDispatcher? commandDispatcher;
+
   [ChromeOnly]
   attribute Node? popupNode;
 
   /**
    * These attributes correspond to rangeParent and rangeOffset. They will help
    * you find where in the DOM the popup is happening. Can be accessed only
    * during a popup event. Accessing any other time will be an error.
    */
--- a/dom/webidl/HTMLImageElement.webidl
+++ b/dom/webidl/HTMLImageElement.webidl
@@ -32,16 +32,18 @@ interface HTMLImageElement : HTMLElement
            [CEReactions, SetterThrows]
            attribute DOMString referrerPolicy;
            [CEReactions, SetterThrows]
            attribute boolean isMap;
            [CEReactions, SetterThrows]
            attribute unsigned long width;
            [CEReactions, SetterThrows]
            attribute unsigned long height;
+           [CEReactions, SetterThrows]
+           attribute DOMString decoding;
   readonly attribute unsigned long naturalWidth;
   readonly attribute unsigned long naturalHeight;
   readonly attribute boolean complete;
 };
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
 partial interface HTMLImageElement {
            [CEReactions, SetterThrows]
--- a/dom/webidl/SVGImageElement.webidl
+++ b/dom/webidl/SVGImageElement.webidl
@@ -16,13 +16,15 @@ interface SVGImageElement : SVGGraphicsE
   [Constant]
   readonly attribute SVGAnimatedLength y;
   [Constant]
   readonly attribute SVGAnimatedLength width;
   [Constant]
   readonly attribute SVGAnimatedLength height;
   [Constant]
   readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
+  [CEReactions, SetterThrows]
+  attribute DOMString decoding;
 };
 
 SVGImageElement implements MozImageLoadingContent;
 SVGImageElement implements SVGURIReference;
 
--- a/dom/webidl/TextDecoder.webidl
+++ b/dom/webidl/TextDecoder.webidl
@@ -12,20 +12,23 @@
 
 [Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options),
  Exposed=(Window,Worker,System)]
 interface TextDecoder {
   [Constant]
   readonly attribute DOMString encoding;
   [Constant]
   readonly attribute boolean fatal;
+  [Constant]
+  readonly attribute boolean ignoreBOM;
   [Throws]
   USVString decode(optional BufferSource input, optional TextDecodeOptions options);
 };
 
 dictionary TextDecoderOptions {
   boolean fatal = false;
+  boolean ignoreBOM = false;
 };
 
 dictionary TextDecodeOptions {
   boolean stream = false;
 };
 
--- a/dom/webidl/TreeBoxObject.webidl
+++ b/dom/webidl/TreeBoxObject.webidl
@@ -1,17 +1,16 @@
 
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 interface MozTreeView;
-interface nsIScriptableRegion;
 
 dictionary TreeCellInfo {
     long row = 0;
     TreeColumn? col = null;
     DOMString childElt = "";
 };
 
 [NoInterfaceObject]
@@ -51,21 +50,16 @@ interface TreeBoxObject : BoxObject {
   readonly attribute long rowWidth;
 
   /**
    * Get the pixel position of the horizontal scrollbar.
    */
   readonly attribute long horizontalPosition;
 
   /**
-   * Return the region for the visible parts of the selection, in device pixels
-   */
-  readonly attribute nsIScriptableRegion selectionRegion;
-
-  /**
    * Get the index of the first visible row.
    */
   long getFirstVisibleRow();
 
   /**
    * Get the index of the last visible row.
    */
   long getLastVisibleRow();
--- a/dom/webidl/XULDocument.webidl
+++ b/dom/webidl/XULDocument.webidl
@@ -5,16 +5,14 @@
  */
 
 interface XULCommandDispatcher;
 interface MozObserver;
 
 [Func="IsChromeOrXBL"]
 interface XULDocument : Document {
 
-  readonly attribute XULCommandDispatcher? commandDispatcher;
-
   [Throws]
   void addBroadcastListenerFor(Element broadcaster, Element observer,
                                DOMString attr);
   void removeBroadcastListenerFor(Element broadcaster, Element observer,
                                   DOMString attr);
 };
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -42,17 +42,16 @@
 #include "nsDocElementCreatedNotificationRunner.h"
 #include "nsNetUtil.h"
 #include "nsParserCIID.h"
 #include "nsPIBoxObject.h"
 #include "mozilla/dom/BoxObject.h"
 #include "nsString.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
-#include "nsXULCommandDispatcher.h"
 #include "nsXULElement.h"
 #include "nsXULPrototypeCache.h"
 #include "mozilla/Logging.h"
 #include "nsIFrame.h"
 #include "nsXBLService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsMimeTypes.h"
 #include "nsIObjectInputStream.h"
@@ -230,24 +229,22 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(XULDocume
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULDocument, XMLDocument)
     NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()),
                  "Shouldn't traverse XULDocument!");
     // XXX tmp->mForwardReferences?
     // XXX tmp->mContextStack?
 
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPrototype)
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypes)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStore)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULDocument, XMLDocument)
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher)
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStore)
     //XXX We should probably unlink all the objects we traverse.
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(XULDocument,
                                              XMLDocument,
                                              nsIStreamLoaderObserver,
                                              nsICSSLoaderObserver,
@@ -1014,26 +1011,17 @@ XULDocument::AddElementToDocumentPre(Ele
     // called when creating elements from prototypes.
     nsAtom* id = aElement->GetID();
     if (id) {
         // FIXME: Shouldn't BindToTree take care of this?
         nsAutoScriptBlocker scriptBlocker;
         AddToIdTable(aElement, id);
     }
 
-    // 2. If the element is a 'command updater' (i.e., has a
-    // "commandupdater='true'" attribute), then add the element to the
-    // document's command dispatcher
-    if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::commandupdater,
-                              nsGkAtoms::_true, eCaseMatters)) {
-        rv = nsXULContentUtils::SetCommandUpdater(this, aElement);
-        if (NS_FAILED(rv)) return rv;
-    }
-
-    // 3. Check for a broadcaster hookup attribute, in which case
+    // 2. Check for a broadcaster hookup attribute, in which case
     // we'll hook the node up as a listener on a broadcaster.
     bool listener, resolved;
     rv = CheckBroadcasterHookup(aElement, &listener, &resolved);
     if (NS_FAILED(rv)) return rv;
 
     // If it's not there yet, we may be able to defer hookup until
     // later.
     if (listener && !resolved && (mResolutionPhase != nsForwardReference::eDone)) {
@@ -1101,17 +1089,17 @@ XULDocument::RemoveSubtreeFromDocument(n
     // Do a bunch of cleanup to remove an element from the XUL
     // document.
     nsresult rv;
 
     if (aElement->NodeInfo()->Equals(nsGkAtoms::keyset, kNameSpaceID_XUL)) {
         nsXBLService::DetachGlobalKeyHandler(aElement);
     }
 
-    // 1. Remove any children from the document.
+    // Remove any children from the document.
     for (nsIContent* child = aElement->GetLastChild();
          child;
          child = child->GetPreviousSibling()) {
 
         rv = RemoveSubtreeFromDocument(child);
         if (NS_FAILED(rv))
             return rv;
     }
@@ -1120,25 +1108,17 @@ XULDocument::RemoveSubtreeFromDocument(n
     // AddElementToDocumentPre().
     nsAtom* id = aElement->GetID();
     if (id) {
         // FIXME: Shouldn't UnbindFromTree take care of this?
         nsAutoScriptBlocker scriptBlocker;
         RemoveFromIdTable(aElement, id);
     }
 
-    // 3. If the element is a 'command updater', then remove the
-    // element from the document's command dispatcher.
-    if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::commandupdater,
-                              nsGkAtoms::_true, eCaseMatters)) {
-        rv = mCommandDispatcher->RemoveCommandUpdater(aElement);
-        if (NS_FAILED(rv)) return rv;
-    }
-
-    // 4. Remove the element from our broadcaster map, since it is no longer
+    // Remove the element from our broadcaster map, since it is no longer
     // in the document.
     nsCOMPtr<Element> broadcaster, listener;
     nsAutoString attribute, broadcasterID;
     rv = FindBroadcaster(aElement, getter_AddRefs(listener),
                          broadcasterID, attribute, getter_AddRefs(broadcaster));
     if (rv == NS_FINDBROADCASTER_FOUND) {
         RemoveBroadcastListenerFor(*broadcaster, *listener, attribute);
     }
@@ -1166,19 +1146,16 @@ XULDocument::Clone(mozilla::dom::NodeInf
 //
 
 nsresult
 XULDocument::Init()
 {
     nsresult rv = XMLDocument::Init();
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Create our command dispatcher and hook it up.
-    mCommandDispatcher = new nsXULCommandDispatcher(this);
-
     if (gRefCnt++ == 0) {
         // ensure that the XUL prototype cache is instantiated successfully,
         // so that we can use nsXULPrototypeCache::GetInstance() without
         // null-checks in the rest of the class.
         nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
         if (!cache) {
           NS_ERROR("Could not instantiate nsXULPrototypeCache");
           return NS_ERROR_FAILURE;
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -10,17 +10,16 @@
 #include "nsCOMPtr.h"
 #include "nsXULPrototypeDocument.h"
 #include "nsTArray.h"
 
 #include "mozilla/dom/XMLDocument.h"
 #include "mozilla/StyleSheet.h"
 #include "nsForwardReference.h"
 #include "nsIContent.h"
-#include "nsIDOMXULCommandDispatcher.h"
 #include "nsCOMArray.h"
 #include "nsIURI.h"
 #include "nsIStreamListener.h"
 #include "nsIStreamLoader.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsIXULStore.h"
 
 #include "mozilla/Attributes.h"
@@ -131,20 +130,16 @@ public:
 
     NS_IMETHOD OnScriptCompileComplete(JSScript* aScript, nsresult aStatus) override;
 
     NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULDocument, XMLDocument)
 
     void TraceProtos(JSTracer* aTrc);
 
     // WebIDL API
-    nsIDOMXULCommandDispatcher* GetCommandDispatcher() const
-    {
-        return mCommandDispatcher;
-    }
     void AddBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
                                  const nsAString& aAttr, ErrorResult& aRv);
     void RemoveBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
                                     const nsAString& aAttr);
 
 protected:
     virtual ~XULDocument();
 
@@ -215,18 +210,16 @@ protected:
      * Since ResumeWalk is interruptible, it's possible that last
      * stylesheet finishes loading while the PD walk is still in
      * progress (waiting for an overlay to finish loading).
      * mStillWalking prevents DoneLoading (and StartLayout) from being
      * called in this situation.
      */
     bool                       mStillWalking;
 
-    nsCOMPtr<nsIDOMXULCommandDispatcher>     mCommandDispatcher; // [OWNER] of the focus tracker
-
     uint32_t mPendingSheets;
 
     /**
      * document lightweight theme for use with :-moz-lwtheme, :-moz-lwtheme-brighttext
      * and :-moz-lwtheme-darktext
      */
     DocumentTheme                         mDocLWTheme;
 
--- a/dom/xul/moz.build
+++ b/dom/xul/moz.build
@@ -11,16 +11,17 @@ if CONFIG['MOZ_BUILD_APP'] == 'browser':
     DEFINES['MOZ_BREAK_XUL_OVERLAYS'] = True
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 if CONFIG['MOZ_XUL']:
     EXPORTS += [
+        'nsXULCommandDispatcher.h',
         'nsXULElement.h',
     ]
 
     EXPORTS.mozilla.dom += [
         'XULFrameElement.h',
         'XULPopupElement.h',
         'XULScrollElement.h',
     ]
--- a/dom/xul/nsXULContentUtils.cpp
+++ b/dom/xul/nsXULContentUtils.cpp
@@ -81,53 +81,8 @@ nsXULContentUtils::FindChildByTag(nsICon
             NS_ADDREF(*aResult = child->AsElement());
             return NS_OK;
         }
     }
 
     *aResult = nullptr;
     return NS_RDF_NO_VALUE; // not found
 }
-
-nsresult
-nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, Element* aElement)
-{
-    // Deal with setting up a 'commandupdater'. Pulls the 'events' and
-    // 'targets' attributes off of aElement, and adds it to the
-    // document's command dispatcher.
-    MOZ_ASSERT(aDocument != nullptr, "null ptr");
-    if (! aDocument)
-        return NS_ERROR_NULL_POINTER;
-
-    MOZ_ASSERT(aElement != nullptr, "null ptr");
-    if (! aElement)
-        return NS_ERROR_NULL_POINTER;
-
-    nsresult rv;
-
-    NS_ASSERTION(aDocument->IsXULDocument(), "not a xul document");
-    if (! aDocument->IsXULDocument())
-        return NS_ERROR_UNEXPECTED;
-
-    XULDocument* xuldoc = aDocument->AsXULDocument();
-    nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher =
-        xuldoc->GetCommandDispatcher();
-    NS_ASSERTION(dispatcher != nullptr, "no dispatcher");
-    if (! dispatcher)
-        return NS_ERROR_UNEXPECTED;
-
-    nsAutoString events;
-    aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events);
-    if (events.IsEmpty())
-        events.Assign('*');
-
-    nsAutoString targets;
-    aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::targets, targets);
-
-    if (targets.IsEmpty())
-        targets.Assign('*');
-
-    rv = dispatcher->AddCommandUpdater(aElement, events, targets);
-    if (NS_FAILED(rv)) return rv;
-
-    return NS_OK;
-}
-
--- a/dom/xul/nsXULContentUtils.h
+++ b/dom/xul/nsXULContentUtils.h
@@ -40,16 +40,13 @@ public:
     Finish();
 
     static nsresult
     FindChildByTag(nsIContent *aElement,
                    int32_t aNameSpaceID,
                    nsAtom* aTag,
                    mozilla::dom::Element** aResult);
 
-    static nsresult
-    SetCommandUpdater(nsIDocument* aDocument, mozilla::dom::Element* aElement);
-
     static nsICollation*
     GetCollation();
 };
 
 #endif // nsXULContentUtils_h__
--- a/gfx/2d/RectAbsolute.h
+++ b/gfx/2d/RectAbsolute.h
@@ -51,16 +51,26 @@ public:
   MOZ_ALWAYS_INLINE const T& Left() const { return left; }
   MOZ_ALWAYS_INLINE const T& Right() const { return right; }
   MOZ_ALWAYS_INLINE const T& Top() const { return top; }
   MOZ_ALWAYS_INLINE const T& Bottom() const { return bottom; }
   MOZ_ALWAYS_INLINE T& Left() { return left; }
   MOZ_ALWAYS_INLINE T& Right() { return right; }
   MOZ_ALWAYS_INLINE T& Top() { return top; }
   MOZ_ALWAYS_INLINE T& Bottom() { return bottom; }
+  T Area() const { return Width() * Height(); }
+
+  void Inflate(T aD) { Inflate(aD, aD); }
+  void Inflate(T aDx, T aDy)
+  {
+    left -= aDx;
+    top -= aDy;
+    right += aDx;
+    bottom += aDy;
+  }
 
   MOZ_ALWAYS_INLINE void SetBox(T aLeft, T aTop, T aRight, T aBottom)
   {
     left = aLeft; top = aTop; right = aRight; bottom = aBottom;
   }
   void SetLeftEdge(T aLeft)
   {
     left = aLeft;
@@ -75,39 +85,175 @@ public:
   }
   void SetBottomEdge(T aBottom)
   {
     bottom = aBottom;
   }
 
   static Sub FromRect(const Rect& aRect)
   {
-    MOZ_ASSERT(!aRect.Overflows());
+    if (aRect.Overflows()) {
+      return Sub();
+    }
     return Sub(aRect.x, aRect.y, aRect.XMost(), aRect.YMost());
   }
 
   MOZ_MUST_USE Sub Intersect(const Sub& aOther) const
   {
     Sub result;
     result.left = std::max<T>(left, aOther.left);
     result.top = std::max<T>(top, aOther.top);
     result.right = std::min<T>(right, aOther.right);
     result.bottom = std::min<T>(bottom, aOther.bottom);
+    if (result.right < result.left || result.bottom < result.top) {
+      result.SizeTo(0, 0);
+    }
     return result;
   }
 
   bool IsEmpty() const {
     return right <= left || bottom <= top;
   }
 
   bool IsEqualEdges(const Sub& aOther) const
   {
     return left == aOther.left && top == aOther.top &&
            right == aOther.right && bottom == aOther.bottom;
   }
+
+  bool IsEqualInterior(const Sub& aRect) const
+  {
+    return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
+  }
+
+  MOZ_ALWAYS_INLINE void MoveBy(T aDx, T aDy) { left += aDx; right += aDx; top += aDy; bottom += aDy; }
+  MOZ_ALWAYS_INLINE void MoveBy(const Point& aPoint) { left += aPoint.x; right += aPoint.x; top += aPoint.y; bottom += aPoint.y; }
+  MOZ_ALWAYS_INLINE void SizeTo(T aWidth, T aHeight) { right = left + aWidth; bottom = top + aHeight; }
+
+  bool Contains(const Sub& aRect) const
+  {
+    return aRect.IsEmpty() ||
+      (left <= aRect.left && aRect.right <= right &&
+       top <= aRect.top && aRect.bottom <= bottom);
+  }
+  bool Contains(T aX, T aY) const
+  {
+    return (left <= aX && aX < right &&
+            top <= aY && aY < bottom);
+  }
+
+  bool Intersects(const Sub& aRect) const
+  {
+    return !IsEmpty() && !aRect.IsEmpty() &&
+      left < aRect.right && aRect.left < right &&
+      top < aRect.bottom && aRect.top < bottom;
+  }
+
+  void SetEmpty() {
+    left = right = top = bottom = 0;
+  }
+
+  // Returns the smallest rectangle that contains both the area of both
+  // this and aRect2.
+  // Thus, empty input rectangles are ignored.
+  // If both rectangles are empty, returns this.
+  // WARNING! This is not safe against overflow, prefer using SafeUnion instead
+  // when dealing with int-based rects.
+  MOZ_MUST_USE Sub Union(const Sub& aRect) const
+  {
+    if (IsEmpty()) {
+      return aRect;
+    } else if (aRect.IsEmpty()) {
+      return *static_cast<const Sub*>(this);
+    } else {
+      return UnionEdges(aRect);
+    }
+  }
+  // Returns the smallest rectangle that contains both the points (including
+  // edges) of both aRect1 and aRect2.
+  // Thus, empty input rectangles are allowed to affect the result.
+  // WARNING! This is not safe against overflow, prefer using SafeUnionEdges
+  // instead when dealing with int-based rects.
+  MOZ_MUST_USE Sub UnionEdges(const Sub& aRect) const
+  {
+    Sub result;
+    result.left = std::min(left, aRect.left);
+    result.top = std::min(top, aRect.top);
+    result.right = std::max(XMost(), aRect.XMost());
+    result.bottom = std::max(YMost(), aRect.YMost());
+    return result;
+  }
+
+  // Scale 'this' by aScale without doing any rounding.
+  void Scale(T aScale) { Scale(aScale, aScale); }
+  // Scale 'this' by aXScale and aYScale, without doing any rounding.
+  void Scale(T aXScale, T aYScale)
+  {
+    right = XMost() * aXScale;
+    bottom = YMost() * aYScale;
+    left = left * aXScale;
+    top = top * aYScale;
+  }
+  // Scale 'this' by aScale, converting coordinates to integers so that the result is
+  // the smallest integer-coordinate rectangle containing the unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
+  void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
+  // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
+  // that the result is the smallest integer-coordinate rectangle containing the
+  // unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
+  void ScaleRoundOut(double aXScale, double aYScale)
+  {
+    right = static_cast<T>(ceil(double(XMost()) * aXScale));
+    bottom = static_cast<T>(ceil(double(YMost()) * aYScale));
+    left = static_cast<T>(floor(double(left) * aXScale));
+    top = static_cast<T>(floor(double(top) * aYScale));
+  }
+  // Scale 'this' by aScale, converting coordinates to integers so that the result is
+  // the largest integer-coordinate rectangle contained by the unrounded result.
+  void ScaleRoundIn(double aScale) { ScaleRoundIn(aScale, aScale); }
+  // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
+  // that the result is the largest integer-coordinate rectangle contained by the
+  // unrounded result.
+  void ScaleRoundIn(double aXScale, double aYScale)
+  {
+    right = static_cast<T>(floor(double(XMost()) * aXScale));
+    bottom = static_cast<T>(floor(double(YMost()) * aYScale));
+    left = static_cast<T>(ceil(double(left) * aXScale));
+    top = static_cast<T>(ceil(double(top) * aYScale));
+  }
+  // Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
+  // the smallest integer-coordinate rectangle containing the unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
+  void ScaleInverseRoundOut(double aScale) { ScaleInverseRoundOut(aScale, aScale); }
+  // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
+  // that the result is the smallest integer-coordinate rectangle containing the
+  // unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
+  void ScaleInverseRoundOut(double aXScale, double aYScale)
+  {
+    right = static_cast<T>(ceil(double(XMost()) / aXScale));
+    bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
+    left = static_cast<T>(floor(double(left) / aXScale));
+    top = static_cast<T>(floor(double(top) / aYScale));
+  }
+  // Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
+  // the largest integer-coordinate rectangle contained by the unrounded result.
+  void ScaleInverseRoundIn(double aScale) { ScaleInverseRoundIn(aScale, aScale); }
+  // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
+  // that the result is the largest integer-coordinate rectangle contained by the
+  // unrounded result.
+  void ScaleInverseRoundIn(double aXScale, double aYScale)
+  {
+    right = static_cast<T>(floor(double(XMost()) / aXScale));
+    bottom = static_cast<T>(floor(double(YMost()) / aYScale));
+    left = static_cast<T>(ceil(double(left) / aXScale));
+    top = static_cast<T>(ceil(double(top) / aYScale));
+  }
+
 };
 
 template <class Units>
 struct IntRectAbsoluteTyped :
     public BaseRectAbsolute<int32_t, IntRectAbsoluteTyped<Units>, IntRectTyped<Units>>,
     public Units {
   static_assert(IsPixel<Units>::value,
                 "'units' must be a coordinate system tag");
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,12 +1,12 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: 7c8f3fc9cf8b79edb241d94a4847968a5009e78d (7.0.0)
+Current revision: b2d8733abf5b141f20881b071b68d2dbe73c5baf (7.1.7)
 
 Upstream files included: LICENSE, src/, include/, tests/*.cc
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
 Additional patch: ots-lz4.patch
--- a/gfx/ots/ots-lz4.patch
+++ b/gfx/ots/ots-lz4.patch
@@ -1,66 +1,74 @@
 diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
 --- a/gfx/ots/src/glat.cc
 +++ b/gfx/ots/src/glat.cc
-@@ -5,7 +5,7 @@
+@@ -4,9 +4,9 @@
+ 
  #include "glat.h"
  
  #include "gloc.h"
 -#include "lz4.h"
 +#include "mozilla/Compression.h"
  #include <list>
  
  namespace ots {
-@@ -201,14 +201,15 @@ bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
+ 
+@@ -200,16 +200,17 @@ bool OpenTypeGLAT_v3::Parse(const uint8_
+       if (prevent_decompression) {
          return DropGraphite("Illegal nested compression");
        }
        std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
 -      int ret = LZ4_decompress_safe_partial(
 +      size_t outputSize = 0;
 +      bool ret = mozilla::Compression::LZ4::decompressPartial(
            reinterpret_cast<const char*>(data + table.offset()),
 -          reinterpret_cast<char*>(decompressed.data()),
            table.remaining(),  // input buffer size (input size + padding)
 +          reinterpret_cast<char*>(decompressed.data()),
            decompressed.size(),  // target output size
 -          decompressed.size());  // output buffer size
--      if (ret != decompressed.size()) {
+-      if (ret < 0 || unsigned(ret) != decompressed.size()) {
 -        return DropGraphite("Decompression failed with error code %d", ret);
 +          &outputSize);  // return output size
 +      if (!ret || outputSize != decompressed.size()) {
 +        return DropGraphite("Decompression failed");
        }
        return this->Parse(decompressed.data(), decompressed.size(), true);
      }
+     default:
 diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
 --- a/gfx/ots/src/silf.cc
 +++ b/gfx/ots/src/silf.cc
-@@ -5,7 +5,7 @@
+@@ -4,9 +4,9 @@
+ 
  #include "silf.h"
  
  #include "name.h"
 -#include "lz4.h"
 +#include "mozilla/Compression.h"
  #include <cmath>
  
  namespace ots {
-@@ -39,14 +39,15 @@ bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
+ 
+@@ -38,16 +38,17 @@ bool OpenTypeSILF::Parse(const uint8_t* 
+         if (prevent_decompression) {
            return DropGraphite("Illegal nested compression");
          }
          std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
 -        int ret = LZ4_decompress_safe_partial(
 +        size_t outputSize = 0;
 +        bool ret = mozilla::Compression::LZ4::decompressPartial(
              reinterpret_cast<const char*>(data + table.offset()),
 -            reinterpret_cast<char*>(decompressed.data()),
              table.remaining(),  // input buffer size (input size + padding)
 +            reinterpret_cast<char*>(decompressed.data()),
              decompressed.size(),  // target output size
 -            decompressed.size());  // output buffer size
--        if (ret != decompressed.size()) {
+-        if (ret < 0 || unsigned(ret) != decompressed.size()) {
 -          return DropGraphite("Decompression failed with error code %d", ret);
 +            &outputSize);   // return output size
 +        if (!ret || outputSize != decompressed.size()) {
 +          return DropGraphite("Decompression failed");
          }
          return this->Parse(decompressed.data(), decompressed.size(), true);
        }
+       default:
--- a/gfx/ots/ots-visibility.patch
+++ b/gfx/ots/ots-visibility.patch
@@ -1,12 +1,13 @@
 diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
 --- a/gfx/ots/include/opentype-sanitiser.h
 +++ b/gfx/ots/include/opentype-sanitiser.h
-@@ -5,6 +5,26 @@
+@@ -4,8 +4,28 @@
+ 
  #ifndef OPENTYPE_SANITISER_H_
  #define OPENTYPE_SANITISER_H_
  
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +  #define OTS_DLL_IMPORT __declspec(dllimport)
 +  #define OTS_DLL_EXPORT __declspec(dllexport)
 +#else
 +  #if __GNUC__ >= 4
@@ -23,17 +24,20 @@ diff --git a/gfx/ots/include/opentype-sa
 +  #endif
 +#else
 +  #define OTS_API
 +#endif
 +
  #if defined(_WIN32)
  #include <stdlib.h>
  typedef signed char int8_t;
-@@ -161,7 +181,7 @@ enum TableAction {
+ typedef unsigned char uint8_t;
+@@ -164,9 +184,9 @@ enum TableAction {
+   TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
    TABLE_ACTION_DROP      // Drop the table
  };
  
 -class OTSContext {
 +class OTS_API OTSContext {
    public:
      OTSContext() {}
      virtual ~OTSContext() {}
+ 
--- a/gfx/ots/src/graphite.h
+++ b/gfx/ots/src/graphite.h
@@ -9,16 +9,17 @@
 #include <type_traits>
 
 namespace ots {
 
 template<typename ParentType>
 class TablePart {
  public:
   TablePart(ParentType* parent) : parent(parent) { }
+  virtual ~TablePart() { }
   virtual bool ParsePart(Buffer& table) = 0;
   virtual bool SerializePart(OTSStream* out) const = 0;
  protected:
   ParentType* parent;
 };
 
 template<typename T>
 bool SerializeParts(const std::vector<T>& vec, OTSStream* out) {
--- a/gfx/ots/src/layout.cc
+++ b/gfx/ots/src/layout.cc
@@ -1388,20 +1388,20 @@ bool ParseDeviceTable(const ots::Font *f
   }
   if (delta_format == kVariationIndex) {
     // start_size and end_size are replaced by deltaSetOuterIndex
     // and deltaSetInnerIndex respectively, but we don't attempt to
     // check them here, so nothing more to do.
     return true;
   }
   if (start_size > end_size) {
-    return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size);
+    return OTS_FAILURE_MSG("Bad device table size range: %u > %u", start_size, end_size);
   }
   if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
-    return OTS_FAILURE_MSG("bad delta format: %u", delta_format);
+    return OTS_FAILURE_MSG("Bad device table delta format: 0x%x", delta_format);
   }
   // The number of delta values per uint16. The device table should contain
   // at least |num_units| * 2 bytes compressed data.
   const unsigned num_units = (end_size - start_size) /
       (1 << (4 - delta_format)) + 1;
   // Just skip |num_units| * 2 bytes since the compressed data could take
   // arbitrary values.
   if (!subtable.Skip(num_units * 2)) {
--- a/gfx/ots/src/os2.cc
+++ b/gfx/ots/src/os2.cc
@@ -147,17 +147,17 @@ bool OpenTypeOS2::Parse(const uint8_t *d
       head && (head->mac_style & 0x3)) {
     Warning("Adjusting head.macStyle (regular) to match fsSelection");
     head->mac_style &= 0xfffcu;
   }
 
   if ((this->table.version < 4) &&
       (this->table.selection & 0x300)) {
     // bit 8 and 9 must be unset in OS/2 table versions less than 4.
-    Warning("fSelection bits 8 and 9 must be unset for table version %d",
+    Warning("fsSelection bits 8 and 9 must be unset for table version %d",
             this->table.version);
   }
 
   // mask reserved bits. use only 0..9 bits.
   this->table.selection &= 0x3ff;
 
   if (this->table.first_char_index > this->table.last_char_index) {
     Warning("usFirstCharIndex %d > usLastCharIndex %d",
--- a/gfx/src/nsRect.h
+++ b/gfx/src/nsRect.h
@@ -125,17 +125,17 @@ struct nsRect :
   {
     return Super::Union(aRect);
   }
   void UnionRect(const nsRect& aRect1, const nsRect& aRect2)
   {
     *this = aRect1.Union(aRect2);
   }
 
-#if defined(_MSC_VER) && !defined(__clang__)
+#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_X64) || defined(_M_IX86))
   // Only MSVC supports inlining intrinsics for archs you're not compiling for.
   MOZ_MUST_USE nsRect Intersect(const nsRect& aRect) const
   {
     nsRect result;
     if (mozilla::gfx::Factory::HasSSE4()) {
       __m128i rect1 = _mm_loadu_si128((__m128i*)&aRect); // x1, y1, w1, h1
       __m128i rect2 = _mm_loadu_si128((__m128i*)this); // x2, y2, w2, h2
 
--- a/gfx/src/nsRectAbsolute.h
+++ b/gfx/src/nsRectAbsolute.h
@@ -13,11 +13,44 @@
 
 struct nsRectAbsolute :
   public mozilla::gfx::BaseRectAbsolute<nscoord, nsRectAbsolute, nsRect> {
   typedef mozilla::gfx::BaseRectAbsolute<nscoord, nsRectAbsolute, nsRect> Super;
 
   nsRectAbsolute() : Super() {}
   nsRectAbsolute(nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2) :
       Super(aX1, aY1, aX2, aY2) {}
+
+  MOZ_ALWAYS_INLINE nscoord SafeWidth() const
+  {
+    int64_t width = right;
+    width -= left;
+    return nscoord(std::min<int64_t>(std::numeric_limits<nscoord>::max(), width));
+  }
+  MOZ_ALWAYS_INLINE nscoord SafeHeight() const
+  {
+    int64_t height = bottom;
+    height -= top;
+    return nscoord(std::min<int64_t>(std::numeric_limits<nscoord>::max(), height));
+  }
+
+  nsRect ToNSRect() const
+  {
+    return nsRect(left, top, nscoord(SafeWidth()), nscoord(SafeHeight()));
+  }
+
+  MOZ_MUST_USE nsRectAbsolute UnsafeUnion(const nsRectAbsolute& aRect) const
+  {
+    return Super::Union(aRect);
+  }
+
+  MOZ_ALWAYS_INLINE void MoveBy(const nsPoint& aPoint) { left += aPoint.x; right += aPoint.x; top += aPoint.y; bottom += aPoint.y; }
+
+  void Inflate(const nsMargin& aMargin)
+  {
+    left -= aMargin.left;
+    top -= aMargin.top;
+    right += aMargin.right;
+    bottom += aMargin.bottom;
+  }
 };
 
 #endif /* NSRECTABSOLUTE_H */
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -58,17 +58,17 @@ nsRegion::AssertStateInternal() const
       }
       lastX = strip.right;
     }
     if (failed) {
       break;
     }
   }
 
-  if (!(mBounds == CalculateBounds())) {
+  if (!(mBounds.IsEqualEdges(CalculateBounds()))) {
     failed = true;
   }
 
   if (failed) {
 #ifdef DEBUG_REGIONS
     if (mCurrentOpGenerator) {
       mCurrentOpGenerator->OutputOp();
     }
@@ -84,17 +84,17 @@ bool nsRegion::Contains(const nsRegion& 
   for (auto iter = aRgn.RectIter(); !iter.Done(); iter.Next()) {
     if (!Contains(iter.Get())) {
       return false;
     }
   }
   return true;
 }
 
-bool nsRegion::Intersects(const nsRect& aRect) const
+bool nsRegion::Intersects(const nsRectAbsolute& aRect) const
 {
   if (mBands.IsEmpty()) {
     return mBounds.Intersects(aRect);
   }
 
   if (!mBounds.Intersects(aRect)) {
     return false;
   }
@@ -125,17 +125,17 @@ bool nsRegion::Intersects(const nsRect& 
 
   return false;
 }
 
 void nsRegion::Inflate(const nsMargin& aMargin)
 {
   nsRegion newRegion;
   for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
-    nsRect rect = iter.Get();
+    nsRectAbsolute rect = iter.GetAbsolute();
     rect.Inflate(aMargin);
     newRegion.AddRect(rect);
   }
 
   *this = std::move(newRegion);
 }
 
 void nsRegion::SimplifyOutward (uint32_t aMaxRects)
@@ -484,30 +484,30 @@ nsRegion& nsRegion::ScaleRoundOut (float
 {
   if (mozilla::gfx::FuzzyEqual(aXScale, 1.0f) &&
       mozilla::gfx::FuzzyEqual(aYScale, 1.0f)) {
     return *this;
   }
 
   nsRegion newRegion;
   for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
-    nsRect rect = iter.Get();
+    nsRectAbsolute rect = iter.GetAbsolute();
     rect.ScaleRoundOut(aXScale, aYScale);
     newRegion.AddRect(rect);
   }
 
   *this = std::move(newRegion);
   return *this;
 }
 
 nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
 {
   nsRegion newRegion;
   for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
-    nsRect rect = iter.Get();
+    nsRectAbsolute rect = iter.GetAbsolute();
     rect.ScaleInverseRoundOut(aXScale, aYScale);
     newRegion.AddRect(rect);
   }
 
   *this = std::move(newRegion);
   return *this;
 }
 
@@ -530,50 +530,50 @@ TransformRect(const mozilla::gfx::IntRec
     return intRect;
 }
 
 nsRegion& nsRegion::Transform (const mozilla::gfx::Matrix4x4 &aTransform)
 {
   nsRegion newRegion;
   for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
     nsRect rect = nsIntRegion::ToRect(TransformRect(nsIntRegion::FromRect(iter.Get()), aTransform));
-    newRegion.AddRect(rect);
+    newRegion.AddRect(nsRectAbsolute::FromRect(rect));
   }
 
   *this = std::move(newRegion);
   return *this;
 }
 
 
 nsRegion nsRegion::ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
   nsRegion newRegion;
   for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
     nsRect rect = iter.Get();
     rect = rect.ScaleToOtherAppUnitsRoundOut(aFromAPP, aToAPP);
-    newRegion.AddRect(rect);
+    newRegion.AddRect(nsRectAbsolute::FromRect(rect));
   }
 
   return newRegion;
 }
 
 nsRegion nsRegion::ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
 
   nsRegion newRegion;
   for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
     nsRect rect = iter.Get();
     rect = rect.ScaleToOtherAppUnitsRoundIn(aFromAPP, aToAPP);
-    newRegion.AddRect(rect);
+    newRegion.AddRect(nsRectAbsolute::FromRect(rect));
   }
 
   return newRegion;
 }
 
 nsIntRegion nsRegion::ToPixels (nscoord aAppUnitsPerPixel, bool aOutsidePixels) const
 {
   nsIntRegion intRegion;
@@ -636,17 +636,17 @@ nsIntRegion nsRegion::ScaleToInsidePixel
    * If it is, then the contained edge can be moved (in scaled pixels) to ensure that no
    * gap exists.
    *
    * Since this could be potentially expensive - O(n^2), we only attempt this algorithm
    * for the first rect.
    */
 
   if (mBands.IsEmpty()) {
-    nsIntRect rect = mBounds.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
+    nsIntRect rect = mBounds.ToNSRect().ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
     return nsIntRegion(rect);
   }
 
   nsIntRegion intRegion;
   RectIterator iter = RectIterator(*this);
 
   nsRect first = iter.Get();
 
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -11,16 +11,17 @@
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint64_t
 #include <sys/types.h>                  // for int32_t
 #include <ostream>                      // for std::ostream
 #include "nsCoord.h"                    // for nscoord
 #include "nsError.h"                    // for nsresult
 #include "nsPoint.h"                    // for nsIntPoint, nsPoint
 #include "nsRect.h"                     // for mozilla::gfx::IntRect, nsRect
+#include "nsRectAbsolute.h"
 #include "nsMargin.h"                   // for nsIntMargin
 #include "nsRegionFwd.h"                // for nsIntRegion
 #include "nsString.h"                   // for nsCString
 #include "xpcom-config.h"               // for CPP_THROW_NEW
 #include "mozilla/ArrayView.h"          // for ArrayView
 #include "mozilla/Move.h"               // for mozilla::Move
 #include "mozilla/gfx/MatrixFwd.h"      // for mozilla::gfx::Matrix4x4
 #include "mozilla/gfx/Logging.h"
@@ -115,17 +116,17 @@ struct Band
 {
   using Strip = regiondetails::Strip;
 #ifndef DEBUG
   using StripArray = regiondetails::UncheckedArray<AutoTArray<Strip, 2>, Strip>;
 #else
   using StripArray = AutoTArray<Strip, 2>;
 #endif
 
-  MOZ_IMPLICIT Band(const nsRect& aRect)
+  MOZ_IMPLICIT Band(const nsRectAbsolute& aRect)
     : top(aRect.Y()), bottom(aRect.YMost())
   {
     mStrips.AppendElement(Strip{ aRect.X(), aRect.XMost() });
   }
 
   Band(const Band& aOther)
     : top(aOther.top), bottom(aOther.bottom)
     , mStrips(aOther.mStrips)
@@ -506,16 +507,19 @@ public:
 #endif
 
   typedef nsRect RectType;
   typedef nsPoint PointType;
   typedef nsMargin MarginType;
 
   nsRegion() { }
   MOZ_IMPLICIT nsRegion(const nsRect& aRect) {
+    mBounds = nsRectAbsolute::FromRect(aRect);
+  }
+  MOZ_IMPLICIT nsRegion(const nsRectAbsolute& aRect) {
     mBounds = aRect;
   }
   explicit nsRegion(mozilla::gfx::ArrayView<pixman_box32_t> aRects)
   {
     for (uint32_t i = 0; i < aRects.Length(); i++) {
       AddRect(BoxToRect(aRects[i]));
     }
   }
@@ -696,33 +700,33 @@ public:
     }
 
     BandArray newBands;
 
     And(newBands, mBands, aRegion.mBands);
 
     mBands = std::move(newBands);
     if (!mBands.Length()) {
-      mBounds = nsRect();
+      mBounds = nsRectAbsolute();
     } else {
       mBounds = CalculateBounds();
     }
 
     EnsureSimplified();
     AssertState();
     return *this;
   }
 
-  nsRegion& AndWith(const nsRect& aRect)
+  nsRegion& AndWith(const nsRectAbsolute& aRect)
   {
 #ifdef DEBUG_REGIONS
     class OperationStringGeneratorAndWith : public OperationStringGenerator
     {
     public:
-      OperationStringGeneratorAndWith(nsRegion& aRegion, const nsRect& aRect)
+      OperationStringGeneratorAndWith(nsRegion& aRegion, const nsRectAbsolute& aRect)
         : mRegion(&aRegion), mRegionCopy(aRegion), mRect(aRect)
       {
         aRegion.mCurrentOpGenerator = this;
       }
       virtual ~OperationStringGeneratorAndWith()
       {
         mRegion->mCurrentOpGenerator = nullptr;
       }
@@ -732,17 +736,17 @@ public:
         std::stringstream stream;
         mRegionCopy.OutputToStream("r", stream);
         stream << "r.AndWith(nsRect(" << mRect.X() << ", " << mRect.Y() << ", " << mRect.Width() << ", " << mRect.Height() << "));\n";
         gfxCriticalError() << stream.str();
       }
     private:
       nsRegion * mRegion;
       nsRegion mRegionCopy;
-      nsRect mRect;
+      nsRectAbsolute mRect;
     };
 
     OperationStringGeneratorAndWith opGenerator(*this, aRect);
 #endif
     if (aRect.IsEmpty()) {
       SetEmpty();
       return *this;
     }
@@ -796,16 +800,19 @@ public:
       mBounds = CalculateBounds();
     } else {
       mBounds.SetEmpty();
     }
     EnsureSimplified();
     AssertState();
     return *this;
   }
+  nsRegion& AndWith(const nsRect& aRect) {
+    return AndWith(nsRectAbsolute::FromRect(aRect));
+  }
   nsRegion& And(const nsRegion& aRgn1, const nsRegion& aRgn2)
   {
     if (&aRgn1 == this) {
       return AndWith(aRgn2);
     }
 #ifdef DEBUG_REGIONS
     class OperationStringGeneratorAnd : public OperationStringGenerator
     {
@@ -850,39 +857,39 @@ public:
       return And(aRgn2, aRgn1.mBounds);
     } else if (aRgn2.mBands.IsEmpty()) {
       return And(aRgn1, aRgn2.mBounds);
     }
 
     And(mBands, aRgn1.mBands, aRgn2.mBands);
 
     if (!mBands.Length()) {
-      mBounds = nsRect();
+      mBounds = nsRectAbsolute();
     } else {
       mBounds = CalculateBounds();
     }
 
     EnsureSimplified();
     AssertState();
     return *this;
   }
   nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
   {
     return And(aRegion, aRect);
   }
-  nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
+  nsRegion& And(const nsRegion& aRegion, const nsRectAbsolute& aRect)
   {
     if (&aRegion == this) {
       return AndWith(aRect);
     }
 #ifdef DEBUG_REGIONS
     class OperationStringGeneratorAnd : public OperationStringGenerator
     {
     public:
-      OperationStringGeneratorAnd(nsRegion& aThisRegion, const nsRegion& aRegion, const nsRect& aRect)
+      OperationStringGeneratorAnd(nsRegion& aThisRegion, const nsRegion& aRegion, const nsRectAbsolute& aRect)
         : mThisRegion(&aThisRegion), mRegion(aRegion), mRect(aRect)
       {
         aThisRegion.mCurrentOpGenerator = this;
       }
       virtual ~OperationStringGeneratorAnd()
       {
         mThisRegion->mCurrentOpGenerator = nullptr;
       }
@@ -892,17 +899,17 @@ public:
         std::stringstream stream;
         mRegion.OutputToStream("r", stream);
         stream << "nsRegion r2;\nr.And(r2, nsRect(" << mRect.X() << ", " << mRect.Y() << ", " << mRect.Width() << ", " << mRect.Height() << "));\n";
         gfxCriticalError() << stream.str();
       }
     private:
       nsRegion* mThisRegion;
       nsRegion mRegion;
-      nsRect mRect;
+      nsRectAbsolute mRect;
     };
 
     OperationStringGeneratorAnd opGenerator(*this, aRegion, aRect);
 #endif
     mBands.Clear();
 
     if (aRect.IsEmpty()) {
       mBounds.SetEmpty();
@@ -953,52 +960,56 @@ public:
     } else {
       mBounds.SetEmpty();
     }
 
     EnsureSimplified();
     AssertState();
     return *this;
   }
+  nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
+  {
+    return And(aRegion, nsRectAbsolute::FromRect(aRect));
+  }
   nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
   {
     nsRect tmpRect;
 
     tmpRect.IntersectRect(aRect1, aRect2);
     return Copy(tmpRect);
   }
 
   nsRegion& OrWith(const nsRegion& aOther)
   {
     for (RectIterator idx(aOther); !idx.Done(); idx.Next()) {
-      AddRect(idx.Get());
+      AddRect(idx.GetAbsolute());
     }
     return *this;
   }
   nsRegion& OrWith(const nsRect& aOther)
   {
-    AddRect(aOther);
+    AddRect(nsRectAbsolute::FromRect(aOther));
     return *this;
   }
   nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
   {
     if (&aRgn1 != this) {
       *this = aRgn1;
     }
     for (RectIterator idx(aRgn2); !idx.Done(); idx.Next()) {
-      AddRect(idx.Get());
+      AddRect(idx.GetAbsolute());
     }
     return *this;
   }
   nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
   {
     if (&aRegion != this) {
       *this = aRegion;
     }
-    AddRect(aRect);
+    AddRect(nsRectAbsolute::FromRect(aRect));
     return *this;
   }
   nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
   {
     return  Or(aRegion, aRect);
   }
   nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
   {
@@ -1376,17 +1387,17 @@ public:
 
     AssertState();
     EnsureSimplified();
     return *this;
   }
 
 private:
   // Internal helper for executing subtraction.
-  void RunSubtraction(const nsRect& aRect)
+  void RunSubtraction(const nsRectAbsolute& aRect)
   {
     Strip rectStrip(aRect.X(), aRect.XMost());
 
     size_t idx = 0;
 
     while (idx < mBands.Length()) {
       if (mBands[idx].top >= aRect.YMost()) {
         return;
@@ -1443,31 +1454,31 @@ private:
         }
       }
 
       return;
     }
   }
 
 public:
-  nsRegion& SubWith(const nsRect& aRect) {
+  nsRegion& SubWith(const nsRectAbsolute& aRect) {
     if (!mBounds.Intersects(aRect)) {
       return *this;
     }
 
     if (aRect.Contains(mBounds)) {
       SetEmpty();
       return *this;
     }
 
 #ifdef DEBUG_REGIONS
     class OperationStringGeneratorSubWith : public OperationStringGenerator
     {
     public:
-      OperationStringGeneratorSubWith(nsRegion& aRegion, const nsRect& aRect)
+      OperationStringGeneratorSubWith(nsRegion& aRegion, const nsRectAbsolute& aRect)
         : mRegion(&aRegion), mRegionCopy(aRegion), mRect(aRect)
       {
         aRegion.mCurrentOpGenerator = this;
       }
       virtual ~OperationStringGeneratorSubWith()
       {
         mRegion->mCurrentOpGenerator = nullptr;
       }
@@ -1477,50 +1488,50 @@ public:
         std::stringstream stream;
         mRegionCopy.OutputToStream("r", stream);
         stream << "r.SubWith(nsRect(" << mRect.X() << ", " << mRect.Y() << ", " << mRect.Width() << ", " << mRect.Height() << "));\n";
         gfxCriticalError() << stream.str();
       }
     private:
       nsRegion * mRegion;
       nsRegion mRegionCopy;
-      nsRect mRect;
+      nsRectAbsolute mRect;
     };
 
     OperationStringGeneratorSubWith opGenerator(*this, aRect);
 #endif
 
     if (mBands.IsEmpty()) {
       mBands.AppendElement(Band(mBounds));
     }
 
     RunSubtraction(aRect);
 
-    if (aRect.x <= mBounds.x || aRect.y <= mBounds.y ||
+    if (aRect.X() <= mBounds.X() || aRect.Y() <= mBounds.Y() ||
         aRect.XMost() >= mBounds.XMost() || aRect.YMost() >= mBounds.YMost()) {
       mBounds = CalculateBounds();
     }
     EnsureSimplified();
     AssertState();
     return *this;
   }
-  nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
+  nsRegion& Sub(const nsRegion& aRegion, const nsRectAbsolute& aRect)
   {
     if (aRect.Contains(aRegion.mBounds)) {
       SetEmpty();
       return *this;
     }
     if (&aRegion == this) {
       return SubWith(aRect);
     }
 #ifdef DEBUG_REGIONS
     class OperationStringGeneratorSub : public OperationStringGenerator
     {
     public:
-      OperationStringGeneratorSub(nsRegion& aRegion, const nsRegion& aRegionOther, const nsRect& aRect)
+      OperationStringGeneratorSub(nsRegion& aRegion, const nsRegion& aRegionOther, const nsRectAbsolute& aRect)
         : mRegion(&aRegion), mRegionOther(aRegionOther), mRect(aRect)
       {
         aRegion.mCurrentOpGenerator = this;
       }
       virtual ~OperationStringGeneratorSub()
       {
         mRegion->mCurrentOpGenerator = nullptr;
       }
@@ -1530,17 +1541,17 @@ public:
         std::stringstream stream;
         mRegionOther.OutputToStream("r1", stream);
         stream << "nsRegion r2;\nr2.Sub(r1, nsRect(" << mRect.X() << ", " << mRect.Y() << ", " << mRect.Width() << ", " << mRect.Height() << "));\n";
         gfxCriticalError() << stream.str();
       }
     private:
       nsRegion * mRegion;
       nsRegion mRegionOther;
-      nsRect mRect;
+      nsRectAbsolute mRect;
     };
 
     OperationStringGeneratorSub opGenerator(*this, aRegion, aRect);
 #endif
 
     mBands.Clear();
 
     if (aRegion.mBounds.IsEmpty()) {
@@ -1627,26 +1638,43 @@ public:
     } else {
       mBounds = CalculateBounds();
     }
 
     AssertState();
     EnsureSimplified();
     return *this;
   }
+  nsRegion& SubWith(const nsRect& aRect) {
+    return SubWith(nsRectAbsolute::FromRect(aRect));
+  }
   nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
   {
     Copy(aRect);
     return SubWith(aRegion);
   }
+  nsRegion& Sub(const nsRectAbsolute& aRect, const nsRegion& aRegion)
+  {
+    Copy(aRect);
+    return SubWith(aRegion);
+  }
   nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
   {
     Copy(aRect1);
     return SubWith(aRect2);
   }
+  nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
+  {
+    return Sub(aRegion, nsRectAbsolute::FromRect(aRect));
+  }
+  nsRegion& Sub(const nsRectAbsolute& aRect1, const nsRectAbsolute& aRect2)
+  {
+    Copy(aRect1);
+    return SubWith(aRect2);
+  }
 
   /**
    * Returns true if the given point is inside the region. A region
    * created from a rect (x=0, y=0, w=100, h=100) will NOT contain
    * the point x=100, y=100.
    */
   bool Contains(int aX, int aY) const
   {
@@ -1668,17 +1696,17 @@ public:
 
       if (iter->ContainsStrip(Strip(aX, aX + 1))) {
         return true;
       }
       return false;
     }
     return false;
   }
-  bool Contains(const nsRect& aRect) const
+  bool Contains(const nsRectAbsolute& aRect) const
   {
     if (aRect.IsEmpty()) {
       return false;
     }
 
     if (mBands.IsEmpty()) {
       return mBounds.Contains(aRect);
     }
@@ -1721,19 +1749,26 @@ public:
         }
 
         lastY = iter->bottom;
         iter++;
       }
     }
     return false;
   }
+  bool Contains(const nsRect& aRect) const
+  {
+    return Contains(nsRectAbsolute::FromRect(aRect));
+  }
 
   bool Contains(const nsRegion& aRgn) const;
-  bool Intersects(const nsRect& aRect) const;
+  bool Intersects(const nsRectAbsolute& aRect) const;
+  bool Intersects(const nsRect& aRect) const {
+    return Intersects(nsRectAbsolute::FromRect(aRect));
+  }
 
   void MoveBy(int32_t aXOffset, int32_t aYOffset)
   {
     MoveBy(nsPoint(aXOffset, aYOffset));
   }
   void MoveBy(nsPoint aPt)
   {
 #ifdef DEBUG_REGIONS
@@ -1843,17 +1878,18 @@ public:
     uint32_t rects = 0;
 
     for (const Band& band : mBands) {
       rects += band.mStrips.Length();
     }
 
     return rects;
   }
-  const nsRect GetBounds() const { return mBounds; }
+  const nsRect GetBounds() const { return mBounds.ToNSRect(); }
+  const nsRectAbsolute GetAbsoluteBounds() const { return mBounds; }
   uint64_t Area() const;
 
   /**
    * Return this region scaled to a different appunits per pixel (APP) ratio.
    * This applies nsRect::ScaleToOtherAppUnitsRoundOut/In to each rect of the region.
    * @param aFromAPP the APP to scale from
    * @param aToAPP the APP to scale to
    * @note this can turn an empty region into a non-empty region
@@ -1937,40 +1973,46 @@ private:
     mBounds = aRegion.mBounds;
     mBands = aRegion.mBands;
     return *this;
   }
 
   nsRegion& Copy(const nsRect& aRect)
   {
     mBands.Clear();
+    mBounds = nsRectAbsolute::FromRect(aRect);
+    return *this;
+  }
+
+  nsRegion& Copy(const nsRectAbsolute& aRect)
+  {
+    mBands.Clear();
     mBounds = aRect;
     return *this;
   }
 
   void EnsureSimplified() {
     if (mBands.Length() == 1 && mBands.begin()->mStrips.Length() == 1) {
       mBands.Clear();
     }
   }
 
-  static inline nsRect BoxToRect(const pixman_box32_t &aBox)
+  static inline nsRectAbsolute BoxToRect(const pixman_box32_t &aBox)
   {
-    return nsRect(aBox.x1, aBox.y1,
-      aBox.x2 - aBox.x1,
-      aBox.y2 - aBox.y1);
+    return nsRectAbsolute(aBox.x1, aBox.y1,
+                          aBox.x2, aBox.y2);
   }
 
-  void AddRect(const nsRect& aRect)
+  void AddRect(const nsRectAbsolute& aRect)
   {
 #ifdef DEBUG_REGIONS
     class OperationStringGeneratorAddRect : public OperationStringGenerator
     {
     public:
-      OperationStringGeneratorAddRect(nsRegion& aRegion, const nsRect& aRect)
+      OperationStringGeneratorAddRect(nsRegion& aRegion, const nsRectAbsolute& aRect)
         : mRegion(&aRegion), mRegionCopy(aRegion), mRect(aRect)
       {
         aRegion.mCurrentOpGenerator = this;
       }
       virtual ~OperationStringGeneratorAddRect()
       {
         mRegion->mCurrentOpGenerator = nullptr;
       }
@@ -1980,31 +2022,25 @@ private:
         std::stringstream stream;
         mRegionCopy.OutputToStream("r", stream);
         stream << "r.OrWith(nsRect(" << mRect.X() << ", " << mRect.Y() << ", " << mRect.Width() << ", " << mRect.Height() << "));\n";
         gfxCriticalError() << stream.str();
       }
     private:
       nsRegion* mRegion;
       nsRegion mRegionCopy;
-      nsRect mRect;
+      nsRectAbsolute mRect;
     };
 
     OperationStringGeneratorAddRect opGenerator(*this, aRect);
 #endif
     if (aRect.IsEmpty()) {
       return;
     }
 
-    if (aRect.Overflows()) {
-      // We don't accept rects which overflow.
-      gfxWarning() << "Passing overflowing rect to AddRect.";
-      return;
-    }
-
     if (mBands.IsEmpty()) {
       if (mBounds.IsEmpty()) {
         mBounds = aRect;
         return;
       } else if (mBounds.Contains(aRect)) {
         return;
       }
 
@@ -2104,33 +2140,33 @@ private:
     }
 
     AssertState();
     EnsureSimplified();
   }
 
   // Most callers could probably do this on the fly, if this ever shows up
   // in profiles we could optimize this.
-  nsRect CalculateBounds() const
+  nsRectAbsolute CalculateBounds() const
   {
     if (mBands.IsEmpty()) {
       return mBounds;
     }
 
     int32_t top = mBands.begin()->top;
     int32_t bottom = mBands.LastElement().bottom;
 
     int32_t leftMost = mBands.begin()->mStrips.begin()->left;
     int32_t rightMost = mBands.begin()->mStrips.LastElement().right;
     for (const Band& band : mBands) {
       leftMost = std::min(leftMost, band.mStrips.begin()->left);
       rightMost = std::max(rightMost, band.mStrips.LastElement().right);
     }
 
-    return nsRect(leftMost, top, rightMost - leftMost, bottom - top);
+    return nsRectAbsolute(leftMost, top, rightMost, bottom);
   }
 
   static uint32_t ComputeMergedAreaIncrease(const Band& aTopBand,
                                             const Band& aBottomBand);
 
   // Returns true if idx is now referring to the 'next' band
   bool CompressAdjacentBands(size_t& aIdx)
   {
@@ -2159,17 +2195,17 @@ private:
         aIdx--;
       }
     }
   }
 
 
   BandArray mBands;
   // Considering we only ever OR with nsRects, the bounds should fit in an nsRect as well.
-  nsRect mBounds;
+  nsRectAbsolute mBounds;
 #ifdef DEBUG_REGIONS
   friend class OperationStringGenerator;
   OperationStringGenerator* mCurrentOpGenerator;
 #endif
 
 public:
   class RectIterator
   {
@@ -2191,23 +2227,32 @@ public:
       }
     }
 
     bool Done() const { return mIsDone; }
 
     const nsRect Get() const
     {
       if (mRegion.mBands.IsEmpty()) {
-        return mRegion.mBounds;
+        return mRegion.GetBounds();
       }
       return nsRect(mCurrentStrip->left, mCurrentBand->top,
         mCurrentStrip->right - mCurrentStrip->left,
         mCurrentBand->bottom - mCurrentBand->top);
     }
 
+    const nsRectAbsolute GetAbsolute() const
+    {
+      if (mRegion.mBands.IsEmpty()) {
+        return mRegion.mBounds;
+      }
+      return nsRectAbsolute(mCurrentStrip->left, mCurrentBand->top,
+                            mCurrentStrip->right, mCurrentBand->bottom);
+    }
+
     void Next()
     {
       if (mRegion.mBands.IsEmpty()) {
         mIsDone = true;
         return;
       }
 
       mCurrentStrip++;
--- a/gfx/tests/gtest/TestRegion.cpp
+++ b/gfx/tests/gtest/TestRegion.cpp
@@ -219,16 +219,21 @@ TEST(Gfx, RegionIsEqual)
     r1.OrWith(nsRect(100, 60, 50, 50));
     nsRegion r2(nsRect(0, 0, 50, 50));
     r2.OrWith(nsRect(0, 60, 50, 50));
     EXPECT_FALSE(r1.IsEqual(r2));
   }
 }
 
 TEST(Gfx, RegionOrWith) {
+  PR_Sleep(PR_SecondsToInterval(10));
+  {
+    nsRegion r(nsRect(11840, 11840, 4640, -10880));
+    r.OrWith(nsRect(160, 160, 7720, 880));
+  }
   {
     nsRegion r(nsRect(79, 31, 75, 12));
     r.OrWith(nsRect(22, 43, 132, 5));
     r.OrWith(nsRect(22, 48, 125, 3));
     r.OrWith(nsRect(22, 51, 96, 20));
     r.OrWith(nsRect(34, 71, 1, 14));
     r.OrWith(nsRect(26, 85, 53, 1));
     r.OrWith(nsRect(26, 86, 53, 4));
--- a/gfx/thebes/gfxFontMissingGlyphs.cpp
+++ b/gfx/thebes/gfxFontMissingGlyphs.cpp
@@ -238,17 +238,17 @@ gfxFontMissingGlyphs::DrawMissingGlyph(u
     Float halfBorderWidth = BOX_BORDER_WIDTH / 2.0;
     Float borderLeft = rect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth;
     Float borderRight = rect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth;
     Rect borderStrokeRect(borderLeft, rect.Y() + halfBorderWidth,
                           borderRight - borderLeft,
                           rect.Height() - 2.0 * halfBorderWidth);
     if (!borderStrokeRect.IsEmpty()) {
         ColorPattern adjustedColor = color;
-        color.mColor.a *= BOX_BORDER_OPACITY;
+        adjustedColor.mColor.a *= BOX_BORDER_OPACITY;
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
         aDrawTarget.FillRect(borderStrokeRect, adjustedColor);
 #else
         StrokeOptions strokeOptions(BOX_BORDER_WIDTH);
         aDrawTarget.StrokeRect(borderStrokeRect, adjustedColor, strokeOptions);
 #endif
     }
 
--- a/ipc/contentproc/moz.build
+++ b/ipc/contentproc/moz.build
@@ -18,11 +18,8 @@ if CONFIG['OS_ARCH'] == 'WINNT':
         '/xpcom/base',
     ]
 
 if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
     LOCAL_INCLUDES += [
         '/security/sandbox/chromium',
         '/security/sandbox/chromium-shim',
     ]
-
-if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
-    AllowCompilerWarnings()  # workaround for bug 1090497
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -21,22 +21,16 @@ namespace js {
 
 JS_FRIEND_API(bool)
 CurrentThreadCanAccessZone(JS::Zone* zone);
 
 namespace gc {
 
 struct Cell;
 
-/*
- * The low bit is set so this should never equal a normal pointer, and the high
- * bit is set so this should never equal the upper 32 bits of a 64-bit pointer.
- */
-const uint32_t Relocated = uintptr_t(0xbad0bad1);
-
 const size_t ArenaShift = 12;
 const size_t ArenaSize = size_t(1) << ArenaShift;
 const size_t ArenaMask = ArenaSize - 1;
 
 #ifdef JS_GC_SMALL_CHUNK_SIZE
 const size_t ChunkShift = 18;
 #else
 const size_t ChunkShift = 20;
@@ -200,47 +194,57 @@ struct Zone
 
     static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) {
         return reinterpret_cast<JS::shadow::Zone*>(zone);
     }
 };
 
 struct String
 {
-    static const uint32_t NON_ATOM_BIT     = JS_BIT(0);
-    static const uint32_t LINEAR_BIT       = JS_BIT(1);
-    static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
-    static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
-    static const uint32_t EXTERNAL_FLAGS   = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
-    static const uint32_t TYPE_FLAGS_MASK  = JS_BIT(6) - 1;
-    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(5);
-    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(5);
+    static const uint32_t NON_ATOM_BIT     = JS_BIT(1);
+    static const uint32_t LINEAR_BIT       = JS_BIT(4);
+    static const uint32_t INLINE_CHARS_BIT = JS_BIT(6);
+    static const uint32_t LATIN1_CHARS_BIT = JS_BIT(9);
+    static const uint32_t EXTERNAL_FLAGS   = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(8);
+    static const uint32_t TYPE_FLAGS_MASK  = JS_BITMASK(9) - JS_BIT(2) - JS_BIT(0);
+    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(8);
+    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(8);
 
-    uint32_t flags;
-    uint32_t length;
+    uintptr_t flags_;
+  #if JS_BITS_PER_WORD == 32
+    uint32_t length_;
+  #endif
+
     union {
         const JS::Latin1Char* nonInlineCharsLatin1;
         const char16_t* nonInlineCharsTwoByte;
         JS::Latin1Char inlineStorageLatin1[1];
         char16_t inlineStorageTwoByte[1];
     };
     const JSStringFinalizer* externalFinalizer;
 
-    static bool nurseryCellIsString(const js::gc::Cell* cell) {
-        MOZ_ASSERT(IsInsideNursery(cell));
-        return reinterpret_cast<const String*>(cell)->flags & NON_ATOM_BIT;
+    inline uint32_t flags() const {
+        return uint32_t(flags_);
+    }
+    inline uint32_t length() const {
+  #if JS_BITS_PER_WORD == 32
+        return length_;
+  #else
+        return uint32_t(flags_ >> 32);
+  #endif
     }
 
     static bool isPermanentAtom(const js::gc::Cell* cell) {
-        uint32_t flags = reinterpret_cast<const String*>(cell)->flags;
+        uint32_t flags = reinterpret_cast<const String*>(cell)->flags();
         return (flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
     }
 };
 
 struct Symbol {
+    uintptr_t reserved_;
     uint32_t code_;
     static const uint32_t WellKnownAPILimit = 0x80000000;
 
     static bool isWellKnownSymbol(const js::gc::Cell* cell) {
         return reinterpret_cast<const Symbol*>(cell)->code_ < WellKnownAPILimit;
     }
 };
 
--- a/js/public/Realm.h
+++ b/js/public/Realm.h
@@ -68,16 +68,21 @@ GetCompartmentForRealm(Realm* realm)
 }
 
 // Return an object's realm. All objects except cross-compartment wrappers are
 // created in a particular realm, which never changes. Returns null if obj is
 // a cross-compartment wrapper.
 extern JS_PUBLIC_API(Realm*)
 GetObjectRealmOrNull(JSObject* obj);
 
+// Return a script's realm. All scripts are created in a particular realm, which
+// never changes.
+extern JS_PUBLIC_API(Realm*)
+GetScriptRealm(JSScript* script);
+
 // Get the value of the "private data" internal field of the given Realm.
 // This field is initially null and is set using SetRealmPrivate.
 // It's a pointer to embeddding-specific data that SpiderMonkey never uses.
 extern JS_PUBLIC_API(void*)
 GetRealmPrivate(Realm* realm);
 
 // Set the "private data" internal field of the given Realm.
 extern JS_PUBLIC_API(void)
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -786,18 +786,22 @@ js::ArraySetLength(JSContext* cx, Handle
             if (!arr->maybeCopyElementsForWrite(cx))
                 return false;
 
             uint32_t oldCapacity = arr->getDenseCapacity();
             uint32_t oldInitializedLength = arr->getDenseInitializedLength();
             MOZ_ASSERT(oldCapacity >= oldInitializedLength);
             if (oldInitializedLength > newLen)
                 arr->setDenseInitializedLengthMaybeNonExtensible(cx, newLen);
-            if (oldCapacity > newLen)
-                arr->shrinkElements(cx, newLen);
+            if (oldCapacity > newLen) {
+                if (arr->isExtensible())
+                    arr->shrinkElements(cx, newLen);
+                else
+                    MOZ_ASSERT(arr->getDenseInitializedLength() == arr->getDenseCapacity());
+            }
 
             // We've done the work of deleting any dense elements needing
             // deletion, and there are no sparse elements.  Thus we can skip
             // straight to defining the length.
             break;
         }
 
         // Step 15.
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -1638,31 +1638,32 @@ ArrayObject* ModuleBuilder::createArray(
     uint32_t i = 0;
     for (auto r = map.all(); !r.empty(); r.popFront())
         array->initDenseElement(i++, ObjectValue(*r.front().value()));
 
     return array;
 }
 
 JSObject*
-js::GetOrCreateModuleMetaObject(JSContext* cx, HandleObject moduleArg)
+js::GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script)
 {
-    HandleModuleObject module = moduleArg.as<ModuleObject>();
+    MOZ_ASSERT(script->module());
+    RootedModuleObject module(cx, script->module());
     if (JSObject* obj = module->metaObject())
         return obj;
 
     RootedObject metaObject(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
     if (!metaObject)
         return nullptr;
 
     JS::ModuleMetadataHook func = cx->runtime()->moduleMetadataHook;
     if (!func) {
         JS_ReportErrorASCII(cx, "Module metadata hook not set");
         return nullptr;
     }
 
-    if (!func(cx, module, metaObject))
+    if (!func(cx, script, metaObject))
         return nullptr;
 
     module->setMetaObject(metaObject);
 
     return metaObject;
 }
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -407,17 +407,17 @@ class MOZ_STACK_CLASS ModuleBuilder
 
     template <typename T>
     ArrayObject* createArray(const JS::Rooted<GCVector<T>>& vector);
     template <typename K, typename V>
     ArrayObject* createArray(const JS::Rooted<GCHashMap<K, V>>& map);
 };
 
 JSObject*
-GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
+GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script);
 
 } // namespace js
 
 template<>
 inline bool
 JSObject::is<js::ModuleNamespaceObject>() const
 {
     return js::IsDerivedProxyObject(this, &js::ModuleNamespaceObject::proxyHandler);
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -791,17 +791,17 @@ WasmHasTier2CompilationCompleted(JSConte
 
     JSObject* unwrapped = CheckedUnwrap(&args.get(0).toObject());
     if (!unwrapped || !unwrapped->is<WasmModuleObject>()) {
         JS_ReportErrorASCII(cx, "argument is not a WebAssembly.Module");
         return false;
     }
 
     Rooted<WasmModuleObject*> module(cx, &unwrapped->as<WasmModuleObject>());
-    args.rval().set(BooleanValue(module->module().compilationComplete()));
+    args.rval().set(BooleanValue(!module->module().testingTier2Active()));
     return true;
 }
 
 static bool
 IsLazyFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -42,17 +42,17 @@ class MOZ_STACK_CLASS BytecodeCompiler
     BytecodeCompiler(JSContext* cx,
                      LifoAlloc& alloc,
                      const ReadOnlyCompileOptions& options,
                      SourceBufferHolder& sourceBuffer,
                      HandleScope enclosingScope);
 
     JSScript* compileGlobalScript(ScopeKind scopeKind);
     JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
-    ModuleObject* compileModule();
+    JSScript* compileModule();
     bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
                                    FunctionAsyncKind asyncKind,
                                    const Maybe<uint32_t>& parameterListEnd);
 
     ScriptSourceObject* sourceObjectPtr() const;
 
   private:
     JSScript* compileScript(HandleObject environment, SharedContext* sc);
@@ -389,17 +389,17 @@ BytecodeCompiler::compileGlobalScript(Sc
 JSScript*
 BytecodeCompiler::compileEvalScript(HandleObject environment, HandleScope enclosingScope)
 {
     EvalSharedContext evalsc(cx, environment, enclosingScope,
                              directives, options.extraWarningsOption);
     return compileScript(environment, &evalsc);
 }
 
-ModuleObject*
+JSScript*
 BytecodeCompiler::compileModule()
 {
     if (!createSourceAndParser(ParseGoal::Module))
         return nullptr;
 
     Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
     if (!module)
         return nullptr;
@@ -433,17 +433,17 @@ BytecodeCompiler::compileModule()
 
     module->setInitialEnvironment(env);
 
     // Enqueue an off-thread source compression task after finishing parsing.
     if (!scriptSource->tryCompressOffThread(cx))
         return nullptr;
 
     MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
-    return module;
+    return script;
 }
 
 // Compile a standalone JS function, which might appear as the value of an
 // event handler attribute in an HTML <INPUT> tag, or in a Function()
 // constructor.
 bool
 BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
                                             GeneratorKind generatorKind,
@@ -682,17 +682,17 @@ frontend::CompileEvalScript(JSContext* c
     JSScript* script = compiler.compileEvalScript(environment, enclosingScope);
     if (!script)
         return nullptr;
     assertException.reset();
     return script;
 
 }
 
-ModuleObject*
+JSScript*
 frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& optionsInput,
                         SourceBufferHolder& srcBuf, LifoAlloc& alloc,
                         ScriptSourceObject** sourceObjectOut)
 {
     MOZ_ASSERT(srcBuf.get());
     MOZ_ASSERT_IF(sourceObjectOut, *sourceObjectOut == nullptr);
 
     AutoAssertReportedException assertException(cx);
@@ -700,45 +700,46 @@ frontend::CompileModule(JSContext* cx, c
     CompileOptions options(cx, optionsInput);
     options.maybeMakeStrictMode(true); // ES6 10.2.1 Module code is always strict mode code.
     options.setIsRunOnce(true);
     options.allowHTMLComments = false;
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     BytecodeCompiler compiler(cx, alloc, options, srcBuf, emptyGlobalScope);
     AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
-    ModuleObject* module = compiler.compileModule();
-    if (!module)
+    JSScript* script = compiler.compileModule();
+    if (!script)
         return nullptr;
 
     assertException.reset();
-    return module;
+    return script;
 }
 
-ModuleObject*
+JSScript*
 frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                         SourceBufferHolder& srcBuf)
 {
     AutoAssertReportedException assertException(cx);
 
     if (!GlobalObject::ensureModulePrototypesCreated(cx, cx->global()))
         return nullptr;
 
     LifoAlloc& alloc = cx->tempLifoAlloc();
-    RootedModuleObject module(cx, CompileModule(cx, options, srcBuf, alloc));
-    if (!module)
+    RootedScript script(cx, CompileModule(cx, options, srcBuf, alloc));
+    if (!script)
         return nullptr;
 
     // This happens in GlobalHelperThreadState::finishModuleParseTask() when a
     // module is compiled off thread.
+    RootedModuleObject module(cx, script->module());
     if (!ModuleObject::Freeze(cx, module))
         return nullptr;
 
     assertException.reset();
-    return module;
+    return script;
 }
 
 // When leaving this scope, the given function should either:
 //   * be linked to a fully compiled script
 //   * remain linking to a lazy script
 class MOZ_STACK_CLASS AutoAssertFunctionDelazificationCompletion
 {
 #ifdef DEBUG
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -16,17 +16,16 @@
 #include "vm/TraceLogging.h"
 
 class JSLinearString;
 
 namespace js {
 
 class LazyScript;
 class LifoAlloc;
-class ModuleObject;
 class ScriptSourceObject;
 
 namespace frontend {
 
 class ErrorReporter;
 class FunctionBox;
 class ParseNode;
 
@@ -48,21 +47,21 @@ CompileGlobalBinASTScript(JSContext *cx,
 
 JSScript*
 CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
                   HandleObject scopeChain, HandleScope enclosingScope,
                   const ReadOnlyCompileOptions& options,
                   SourceBufferHolder& srcBuf,
                   ScriptSourceObject** sourceObjectOut = nullptr);
 
-ModuleObject*
+JSScript*
 CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
               SourceBufferHolder& srcBuf);
 
-ModuleObject*
+JSScript*
 CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
               SourceBufferHolder& srcBuf, LifoAlloc& alloc,
               ScriptSourceObject** sourceObjectOut = nullptr);
 
 MOZ_MUST_USE bool
 CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
 
 //
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6065,21 +6065,23 @@ BytecodeEmitter::emitAwaitInScope(Emitte
 }
 
 bool
 BytecodeEmitter::emitYieldStar(ParseNode* iter)
 {
     MOZ_ASSERT(sc->isFunctionBox());
     MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
 
-    bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
+    IteratorKind iterKind = sc->asFunctionBox()->isAsync()
+                            ? IteratorKind::Async
+                            : IteratorKind::Sync;
 
     if (!emitTree(iter))                                  // ITERABLE
         return false;
-    if (isAsyncGenerator) {
+    if (iterKind == IteratorKind::Async) {
         if (!emitAsyncIterator())                         // NEXT ITER
             return false;
     } else {
         if (!emitIterator())                              // NEXT ITER
             return false;
     }
 
     // Initial send value is undefined.
@@ -6097,77 +6099,62 @@ BytecodeEmitter::emitYieldStar(ParseNode
 
     JumpTarget tryStart{ offset() };
     if (!tryCatch.emitTry())                              // NEXT ITER RESULT
         return false;
 
     MOZ_ASSERT(this->stackDepth == startDepth);
 
     // 11.4.3.7 AsyncGeneratorYield step 5.
-    if (isAsyncGenerator) {
+    if (iterKind == IteratorKind::Async) {
         if (!emitAwaitInInnermostScope())                 // NEXT ITER RESULT
             return false;
     }
 
     // Load the generator object.
     if (!emitGetDotGeneratorInInnermostScope())           // NEXT ITER RESULT GENOBJ
         return false;
 
     // Yield RESULT as-is, without re-boxing.
     if (!emitYieldOp(JSOP_YIELD))                         // NEXT ITER RECEIVED
         return false;
 
     if (!tryCatch.emitCatch())                            // NEXT ITER RESULT
         return false;
 
-    stackDepth = startDepth;                              // NEXT ITER RESULT
+    MOZ_ASSERT(stackDepth == startDepth);
+
     if (!emit1(JSOP_EXCEPTION))                           // NEXT ITER RESULT EXCEPTION
         return false;
     if (!emitDupAt(2))                                    // NEXT ITER RESULT EXCEPTION ITER
         return false;
     if (!emit1(JSOP_DUP))                                 // NEXT ITER RESULT EXCEPTION ITER ITER
         return false;
     if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP))   // NEXT ITER RESULT EXCEPTION ITER THROW
         return false;
-    if (!emit1(JSOP_DUP))                                 // NEXT ITER RESULT EXCEPTION ITER THROW THROW
-        return false;
-    if (!emit1(JSOP_UNDEFINED))                           // NEXT ITER RESULT EXCEPTION ITER THROW THROW UNDEFINED
-        return false;
-    if (!emit1(JSOP_EQ))                                  // NEXT ITER RESULT EXCEPTION ITER THROW ?EQL
-        return false;
-
-    InternalIfEmitter ifThrowMethodIsNotDefined(this);
-    if (!ifThrowMethodIsNotDefined.emitThen())            // NEXT ITER RESULT EXCEPTION ITER THROW
-        return false;
+
     savedDepthTemp = stackDepth;
-    if (!emit1(JSOP_POP))                                 // NEXT ITER RESULT EXCEPTION ITER
-        return false;
-    // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
-    //
-    // If the iterator does not have a "throw" method, it calls IteratorClose
-    // and then throws a TypeError.
-    IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
-    if (!emitIteratorCloseInInnermostScope(iterKind))     // NEXT ITER RESULT EXCEPTION
-        return false;
-    if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
-        return false;
-    stackDepth = savedDepthTemp;
-    if (!ifThrowMethodIsNotDefined.emitEnd())             // NEXT ITER OLDRESULT EXCEPTION ITER THROW
-        return false;
+    InternalIfEmitter ifThrowMethodIsNotDefined(this);
+    if (!emitPushNotUndefinedOrNull())                    // NEXT ITER RESULT EXCEPTION ITER THROW NOT-UNDEF-OR-NULL
+        return false;
+
+    if (!ifThrowMethodIsNotDefined.emitThenElse())        // NEXT ITER RESULT EXCEPTION ITER THROW
+        return false;
+
     // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.4.
     // RESULT = ITER.throw(EXCEPTION)                     // NEXT ITER OLDRESULT EXCEPTION ITER THROW
     if (!emit1(JSOP_SWAP))                                // NEXT ITER OLDRESULT EXCEPTION THROW ITER
         return false;
     if (!emit2(JSOP_PICK, 2))                             // NEXT ITER OLDRESULT THROW ITER EXCEPTION
         return false;
     if (!emitCall(JSOP_CALL, 1, iter))                    // NEXT ITER OLDRESULT RESULT
         return false;
     checkTypeSet(JSOP_CALL);
 
-    if (isAsyncGenerator) {
+    if (iterKind == IteratorKind::Async) {
         if (!emitAwaitInInnermostScope())                 // NEXT ITER OLDRESULT RESULT
             return false;
     }
 
     if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) // NEXT ITER OLDRESULT RESULT
         return false;
     if (!emit1(JSOP_SWAP))                                // NEXT ITER RESULT OLDRESULT
         return false;
@@ -6177,16 +6164,36 @@ BytecodeEmitter::emitYieldStar(ParseNode
     JumpList checkResult;
     // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.ii.
     //
     // Note that there is no GOSUB to the finally block here. If the iterator has a
     // "throw" method, it does not perform IteratorClose.
     if (!emitJump(JSOP_GOTO, &checkResult))               // goto checkResult
         return false;
 
+    stackDepth = savedDepthTemp;
+    if (!ifThrowMethodIsNotDefined.emitElse())            // NEXT ITER RESULT EXCEPTION ITER THROW
+        return false;
+
+    if (!emit1(JSOP_POP))                                 // NEXT ITER RESULT EXCEPTION ITER
+        return false;
+    // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
+    //
+    // If the iterator does not have a "throw" method, it calls IteratorClose
+    // and then throws a TypeError.
+    if (!emitIteratorCloseInInnermostScope(iterKind))     // NEXT ITER RESULT EXCEPTION
+        return false;
+    if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
+        return false;
+
+    stackDepth = savedDepthTemp;
+    if (!ifThrowMethodIsNotDefined.emitEnd())
+        return false;
+
+    stackDepth = startDepth;
     if (!tryCatch.emitFinally())
          return false;
 
     // ES 14.4.13, yield * AssignmentExpression, step 5.c
     //
     // Call iterator.return() for receiving a "forced return" completion from
     // the generator.
 
@@ -6298,17 +6305,17 @@ BytecodeEmitter::emitYieldStar(ParseNode
     if (!emit1(JSOP_DUP2))                                       // RECEIVED NEXT ITER NEXT ITER
         return false;
     if (!emit2(JSOP_PICK, 4))                                    // NEXT ITER NEXT ITER RECEIVED
         return false;
     if (!emitCall(JSOP_CALL, 1, iter))                           // NEXT ITER RESULT
         return false;
     checkTypeSet(JSOP_CALL);
 
-    if (isAsyncGenerator) {
+    if (iterKind == IteratorKind::Async) {
         if (!emitAwaitInInnermostScope())                        // NEXT ITER RESULT RESULT
             return false;
     }
 
     if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext))        // NEXT ITER RESULT
         return false;
     MOZ_ASSERT(this->stackDepth == startDepth);
 
--- a/js/src/gc/Cell.h
+++ b/js/src/gc/Cell.h
@@ -43,20 +43,45 @@ TraceManuallyBarrieredGenericPointerEdge
 namespace gc {
 
 class Arena;
 enum class AllocKind : uint8_t;
 struct Chunk;
 class StoreBuffer;
 class TenuredCell;
 
-// A GC cell is the base class for all GC things.
+// [SMDOC] GC Cell
+//
+// A GC cell is the base class for all GC things. All types allocated on the GC
+// heap extend either gc::Cell or gc::TenuredCell. If a type is always tenured,
+// prefer the TenuredCell class as base.
+//
+// The first word (a pointer or uintptr_t) of each Cell must reserve the low
+// Cell::ReservedBits bits for GC purposes. The remaining bits are available to
+// sub-classes and typically store a pointer to another gc::Cell.
+//
+// During moving GC operation a Cell may be marked as forwarded. This indicates
+// that a gc::RelocationOverlay is currently stored in the Cell's memory and
+// should be used to find the new location of the Cell.
 struct alignas(gc::CellAlignBytes) Cell
 {
   public:
+    // The low bits of the first word of each Cell are reserved for GC flags.
+    static constexpr int ReservedBits = 2;
+    static constexpr uintptr_t RESERVED_MASK = JS_BITMASK(ReservedBits);
+
+    // Indicates if the cell is currently a RelocationOverlay
+    static constexpr uintptr_t FORWARD_BIT = JS_BIT(0);
+
+    // When a Cell is in the nursery, this will indicate if it is a JSString (1)
+    // or JSObject (0). When not in nursery, this bit is still reserved for
+    // JSString to use as JSString::NON_ATOM bit. This may be removed by Bug
+    // 1376646.
+    static constexpr uintptr_t JSSTRING_BIT = JS_BIT(1);
+
     MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
     MOZ_ALWAYS_INLINE const TenuredCell& asTenured() const;
     MOZ_ALWAYS_INLINE TenuredCell& asTenured();
 
     MOZ_ALWAYS_INLINE bool isMarkedAny() const;
     MOZ_ALWAYS_INLINE bool isMarkedBlack() const;
     MOZ_ALWAYS_INLINE bool isMarkedGray() const;
 
@@ -72,16 +97,27 @@ struct alignas(gc::CellAlignBytes) Cell
     // The StoreBuffer used to record incoming pointers from the tenured heap.
     // This will return nullptr for a tenured cell.
     inline StoreBuffer* storeBuffer() const;
 
     inline JS::TraceKind getTraceKind() const;
 
     static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
 
+    inline bool isForwarded() const {
+        uintptr_t firstWord = *reinterpret_cast<const uintptr_t*>(this);
+        return firstWord & FORWARD_BIT;
+    }
+
+    inline bool nurseryCellIsString() const {
+        MOZ_ASSERT(!isTenured());
+        uintptr_t firstWord = *reinterpret_cast<const uintptr_t*>(this);
+        return firstWord & JSSTRING_BIT;
+    }
+
     template <class T>
     inline bool is() const {
         return getTraceKind() == JS::MapTypeToTraceKind<T>::kind;
     }
 
     template<class T>
     inline T* as() {
         // |this|-qualify the |is| call below to avoid compile errors with even
@@ -250,17 +286,17 @@ Cell::storeBuffer() const
     return chunk()->trailer.storeBuffer;
 }
 
 inline JS::TraceKind
 Cell::getTraceKind() const
 {
     if (isTenured())
         return asTenured().getTraceKind();
-    if (JS::shadow::String::nurseryCellIsString(this))
+    if (nurseryCellIsString())
         return JS::TraceKind::String;
     return JS::TraceKind::Object;
 }
 
 /* static */ MOZ_ALWAYS_INLINE bool
 Cell::needWriteBarrierPre(JS::Zone* zone) {
     return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier();
 }
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -219,16 +219,17 @@
 #include "gc/GCTrace.h"
 #include "gc/Memory.h"
 #include "gc/Policy.h"
 #include "gc/WeakMap.h"
 #include "jit/BaselineJIT.h"
 #include "jit/IonCode.h"
 #include "jit/JitcodeMap.h"
 #include "jit/JitRealm.h"
+#include "jit/MacroAssembler.h"
 #include "js/SliceBudget.h"
 #include "proxy/DeadObjectProxy.h"
 #include "util/Windows.h"
 #ifdef ENABLE_BIGINT
 #include "vm/BigIntType.h"
 #endif
 #include "vm/Debugger.h"
 #include "vm/GeckoProfiler.h"
@@ -379,16 +380,27 @@ static const int IGC_MARK_SLICE_MULTIPLI
 const AllocKind gc::slotsToThingKind[] = {
     /*  0 */ AllocKind::OBJECT0,  AllocKind::OBJECT2,  AllocKind::OBJECT2,  AllocKind::OBJECT4,
     /*  4 */ AllocKind::OBJECT4,  AllocKind::OBJECT8,  AllocKind::OBJECT8,  AllocKind::OBJECT8,
     /*  8 */ AllocKind::OBJECT8,  AllocKind::OBJECT12, AllocKind::OBJECT12, AllocKind::OBJECT12,
     /* 12 */ AllocKind::OBJECT12, AllocKind::OBJECT16, AllocKind::OBJECT16, AllocKind::OBJECT16,
     /* 16 */ AllocKind::OBJECT16
 };
 
+// Check that reserved bits of a Cell are compatible with our typical allocators
+// since most derived classes will store a pointer in the first word.
+static_assert(js::detail::LIFO_ALLOC_ALIGN > JS_BITMASK(Cell::ReservedBits),
+              "Cell::ReservedBits should support LifoAlloc");
+static_assert(CellAlignBytes > JS_BITMASK(Cell::ReservedBits),
+              "Cell::ReservedBits should support gc::Cell");
+static_assert(sizeof(uintptr_t) > JS_BITMASK(Cell::ReservedBits),
+              "Cell::ReservedBits should support small malloc / aligned globals");
+static_assert(js::jit::CodeAlignment > JS_BITMASK(Cell::ReservedBits),
+              "Cell::ReservedBits should support JIT code");
+
 static_assert(mozilla::ArrayLength(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT,
               "We have defined a slot count for each kind.");
 
 #define CHECK_THING_SIZE(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
     static_assert(sizeof(sizedType) >= SortedArenaList::MinThingSize, \
                   #sizedType " is smaller than SortedArenaList::MinThingSize!"); \
     static_assert(sizeof(sizedType) >= sizeof(FreeSpan), \
                   #sizedType " is smaller than FreeSpan"); \
@@ -2339,17 +2351,17 @@ RelocateArena(Arena* arena, SliceBudget&
     for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
         RelocateCell(zone, i.getCell(), thingKind, thingSize);
         sliceBudget.step();
     }
 
 #ifdef DEBUG
     for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
         TenuredCell* src = i.getCell();
-        MOZ_ASSERT(RelocationOverlay::isCellForwarded(src));
+        MOZ_ASSERT(src->isForwarded());
         TenuredCell* dest = Forwarded(src);
         MOZ_ASSERT(src->isMarkedBlack() == dest->isMarkedBlack());
         MOZ_ASSERT(src->isMarkedGray() == dest->isMarkedGray());
     }
 #endif
 }
 
 static inline bool
@@ -8467,18 +8479,18 @@ js::gc::AssertGCThingHasType(js::gc::Cel
     if (!cell) {
         MOZ_ASSERT(kind == JS::TraceKind::Null);
         return;
     }
 
     MOZ_ASSERT(IsCellPointerValid(cell));
 
     if (IsInsideNursery(cell)) {
-        MOZ_ASSERT(kind == (JSString::nurseryCellIsString(cell) ? JS::TraceKind::String
-                                                                : JS::TraceKind::Object));
+        MOZ_ASSERT(kind == (cell->nurseryCellIsString() ? JS::TraceKind::String
+                                                        : JS::TraceKind::Object));
         return;
     }
 
     MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured().getAllocKind()) == kind);
 }
 #endif
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -172,17 +172,17 @@ struct MovingTracer : JS::CallbackTracer
     void onShapeEdge(Shape** shapep) override;
     void onStringEdge(JSString** stringp) override;
     void onScriptEdge(JSScript** scriptp) override;
     void onLazyScriptEdge(LazyScript** lazyp) override;
     void onBaseShapeEdge(BaseShape** basep) override;
     void onScopeEdge(Scope** basep) override;
     void onRegExpSharedEdge(RegExpShared** sharedp) override;
     void onChild(const JS::GCCellPtr& thing) override {
-        MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
+        MOZ_ASSERT(!thing.asCell()->isForwarded());
     }
 
 #ifdef DEBUG
     TracerKind getTracerKind() const override { return TracerKind::Moving; }
 #endif
 
   private:
     template <typename T>
--- a/js/src/gc/Marking-inl.h
+++ b/js/src/gc/Marking-inl.h
@@ -35,23 +35,22 @@ struct MightBeForwarded
                               mozilla::IsBaseOf<js::Scope, T>::value ||
                               mozilla::IsBaseOf<js::RegExpShared, T>::value;
 };
 
 template <typename T>
 inline bool
 IsForwarded(const T* t)
 {
-    const RelocationOverlay* overlay = RelocationOverlay::fromCell(t);
     if (!MightBeForwarded<T>::value) {
-        MOZ_ASSERT(!overlay->isForwarded());
+        MOZ_ASSERT(!t->isForwarded());
         return false;
     }
 
-    return overlay->isForwarded();
+    return t->isForwarded();
 }
 
 struct IsForwardedFunctor : public BoolDefaultAdaptor<Value, false> {
     template <typename T> bool operator()(const T* t) { return IsForwarded(t); }
 };
 
 inline bool
 IsForwarded(const JS::Value& value)
@@ -88,35 +87,33 @@ MaybeForwarded(T t)
         t = Forwarded(t);
     return t;
 }
 
 inline void
 RelocationOverlay::forwardTo(Cell* cell)
 {
     MOZ_ASSERT(!isForwarded());
-    // The location of magic_ is important because it must never be valid to see
-    // the value Relocated there in a GC thing that has not been moved.
-    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSObject, group_) + sizeof(uint32_t),
-                  "RelocationOverlay::magic_ is in the wrong location");
-    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(js::Shape, base_) + sizeof(uint32_t),
-                  "RelocationOverlay::magic_ is in the wrong location");
-    static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSString, d.u1.length),
-                  "RelocationOverlay::magic_ is in the wrong location");
-    magic_ = Relocated;
-    newLocation_ = cell;
+
+    // Preserve old flags because nursery may check them before checking
+    // if this is a forwarded Cell.
+    //
+    // This is pretty terrible and we should find a better way to implement
+    // Cell::getTrackKind() that doesn't rely on this behavior.
+    uintptr_t gcFlags = dataWithTag_ & Cell::RESERVED_MASK;
+    dataWithTag_ = uintptr_t(cell) | gcFlags | Cell::FORWARD_BIT;
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 template <typename T>
 inline bool
 IsGCThingValidAfterMovingGC(T* t)
 {
-    return !IsInsideNursery(t) && !RelocationOverlay::isCellForwarded(t);
+    return !IsInsideNursery(t) && !t->isForwarded();
 }
 
 template <typename T>
 inline void
 CheckGCThingAfterMovingGC(T* t)
 {
     if (t)
         MOZ_RELEASE_ASSERT(IsGCThingValidAfterMovingGC(t));
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1232,124 +1232,124 @@ WasmFunctionScope::Data::trace(JSTracer*
 }
 void
 Scope::traceChildren(JSTracer* trc)
 {
     TraceNullableEdge(trc, &enclosing_, "scope enclosing");
     TraceNullableEdge(trc, &environmentShape_, "scope env shape");
     switch (kind_) {
       case ScopeKind::Function:
-        reinterpret_cast<FunctionScope::Data*>(data_)->trace(trc);
+        static_cast<FunctionScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::FunctionBodyVar:
       case ScopeKind::ParameterExpressionVar:
-        reinterpret_cast<VarScope::Data*>(data_)->trace(trc);
+        static_cast<VarScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::Lexical:
       case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda:
-        reinterpret_cast<LexicalScope::Data*>(data_)->trace(trc);
+        static_cast<LexicalScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::Global:
       case ScopeKind::NonSyntactic:
-        reinterpret_cast<GlobalScope::Data*>(data_)->trace(trc);
+        static_cast<GlobalScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::Eval:
       case ScopeKind::StrictEval:
-        reinterpret_cast<EvalScope::Data*>(data_)->trace(trc);
+        static_cast<EvalScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::Module:
-        reinterpret_cast<ModuleScope::Data*>(data_)->trace(trc);
+        static_cast<ModuleScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::With:
         break;
       case ScopeKind::WasmInstance:
-        reinterpret_cast<WasmInstanceScope::Data*>(data_)->trace(trc);
+        static_cast<WasmInstanceScope::Data*>(data_)->trace(trc);
         break;
       case ScopeKind::WasmFunction:
-        reinterpret_cast<WasmFunctionScope::Data*>(data_)->trace(trc);
+        static_cast<WasmFunctionScope::Data*>(data_)->trace(trc);
         break;
     }
 }
 inline void
 js::GCMarker::eagerlyMarkChildren(Scope* scope)
 {
     if (scope->enclosing_)
         traverseEdge(scope, static_cast<Scope*>(scope->enclosing_));
     if (scope->environmentShape_)
         traverseEdge(scope, static_cast<Shape*>(scope->environmentShape_));
     TrailingNamesArray* names = nullptr;
     uint32_t length = 0;
     switch (scope->kind_) {
       case ScopeKind::Function: {
-        FunctionScope::Data* data = reinterpret_cast<FunctionScope::Data*>(scope->data_);
+        FunctionScope::Data* data = static_cast<FunctionScope::Data*>(scope->data_);
         traverseEdge(scope, static_cast<JSObject*>(data->canonicalFunction));
         names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::FunctionBodyVar:
       case ScopeKind::ParameterExpressionVar: {
-        VarScope::Data* data = reinterpret_cast<VarScope::Data*>(scope->data_);
+        VarScope::Data* data = static_cast<VarScope::Data*>(scope->data_);
         names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Lexical:
       case ScopeKind::SimpleCatch:
       case ScopeKind::Catch:
       case ScopeKind::NamedLambda:
       case ScopeKind::StrictNamedLambda: {
-        LexicalScope::Data* data = reinterpret_cast<LexicalScope::Data*>(scope->data_);
+        LexicalScope::Data* data = static_cast<LexicalScope::Data*>(scope->data_);
         names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Global:
       case ScopeKind::NonSyntactic: {
-        GlobalScope::Data* data = reinterpret_cast<GlobalScope::Data*>(scope->data_);
+        GlobalScope::Data* data = static_cast<GlobalScope::Data*>(scope->data_);
         names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Eval:
       case ScopeKind::StrictEval: {
-        EvalScope::Data* data = reinterpret_cast<EvalScope::Data*>(scope->data_);
+        EvalScope::Data* data = static_cast<EvalScope::Data*>(scope->data_);
         names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::Module: {
-        ModuleScope::Data* data = reinterpret_cast<ModuleScope::Data*>(scope->data_);
+        ModuleScope::Data* data = static_cast<ModuleScope::Data*>(scope->data_);
         traverseEdge(scope, static_cast<JSObject*>(data->module));
         names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::With:
         break;
 
       case ScopeKind::WasmInstance: {
-        WasmInstanceScope::Data* data = reinterpret_cast<WasmInstanceScope::Data*>(scope->data_);
+        WasmInstanceScope::Data* data = static_cast<WasmInstanceScope::Data*>(scope->data_);
         traverseEdge(scope, static_cast<JSObject*>(data->instance));
         names = &data->trailingNames;
         length = data->length;
         break;
       }
 
       case ScopeKind::WasmFunction: {
-        WasmFunctionScope::Data* data = reinterpret_cast<WasmFunctionScope::Data*>(scope->data_);
+        WasmFunctionScope::Data* data = static_cast<WasmFunctionScope::Data*>(scope->data_);
         names = &data->trailingNames;
         length = data->length;
         break;
       }
     }
     if (scope->kind_ == ScopeKind::Function) {
         for (uint32_t i = 0; i < length; i++) {
             if (JSAtom* name = names->operator[](i).name())
@@ -2857,17 +2857,17 @@ js::gc::StoreBuffer::CellPtrEdge::trace(
 #endif
 
     // Bug 1376646: Make separate store buffers for strings and objects, and
     // only check IsInsideNursery once.
 
     if (!IsInsideNursery(*edge))
         return;
 
-    if (JSString::nurseryCellIsString(*edge))
+    if ((*edge)->nurseryCellIsString())
         mover.traverse(reinterpret_cast<JSString**>(edge));
     else
         mover.traverse(reinterpret_cast<JSObject**>(edge));
 }
 
 void
 js::gc::StoreBuffer::ValueEdge::trace(TenuringTracer& mover) const
 {
--- a/js/src/gc/Nursery-inl.h
+++ b/js/src/gc/Nursery-inl.h
@@ -23,21 +23,21 @@ bool
 js::Nursery::isInside(const SharedMem<T>& p) const
 {
     return isInside(p.unwrap(/*safe - used for value in comparison above*/));
 }
 
 MOZ_ALWAYS_INLINE /* static */ bool
 js::Nursery::getForwardedPointer(js::gc::Cell** ref)
 {
-    MOZ_ASSERT(ref);
-    MOZ_ASSERT(IsInsideNursery(*ref));
-    const gc::RelocationOverlay* overlay = reinterpret_cast<const gc::RelocationOverlay*>(*ref);
-    if (!overlay->isForwarded())
+    js::gc::Cell* cell = (*ref);
+    MOZ_ASSERT(IsInsideNursery(cell));
+    if (!cell->isForwarded())
         return false;
+    const gc::RelocationOverlay* overlay = gc::RelocationOverlay::fromCell(cell);
     *ref = overlay->forwardingAddress();
     return true;
 }
 
 inline void
 js::Nursery::maybeSetForwardingPointer(JSTracer* trc, void* oldData, void* newData, bool direct)
 {
     if (trc->isTenuringTracer())
--- a/js/src/gc/RelocationOverlay.h
+++ b/js/src/gc/RelocationOverlay.h
@@ -11,81 +11,65 @@
 #ifndef gc_RelocationOverlay_h
 #define gc_RelocationOverlay_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/EndianUtils.h"
 
 #include <stdint.h>
 
+#include "gc/Cell.h"
 #include "js/HeapAPI.h"
 #include "vm/JSObject.h"
 #include "vm/Shape.h"
 
 namespace js {
 namespace gc {
 
-struct Cell;
-
 /*
  * This structure overlays a Cell that has been moved and provides a way to find
  * its new location. It's used during generational and compacting GC.
  */
-class RelocationOverlay
+class RelocationOverlay : public Cell
 {
-    /* See comment in js/public/HeapAPI.h. */
-    static const uint32_t Relocated = js::gc::Relocated;
-
-    /*
-     * Keep the low 32 bits untouched. Use them to distinguish strings from
-     * objects in the nursery.
-     */
-    uint32_t preserve_;
-
-    /* Set to Relocated when moved. */
-    uint32_t magic_;
-
-    /* The location |this| was moved to. */
-    Cell* newLocation_;
+    // First word of a Cell has additional requirements from GC. The GC flags
+    // determine if a Cell is a normal entry or is a RelocationOverlay.
+    //                3         0
+    //  -------------------------
+    //  | NewLocation | GCFlags |
+    //  -------------------------
+    uintptr_t dataWithTag_;
 
     /* A list entry to track all relocated things. */
     RelocationOverlay* next_;
 
   public:
     static const RelocationOverlay* fromCell(const Cell* cell) {
-        return reinterpret_cast<const RelocationOverlay*>(cell);
+        return static_cast<const RelocationOverlay*>(cell);
     }
 
     static RelocationOverlay* fromCell(Cell* cell) {
-        return reinterpret_cast<RelocationOverlay*>(cell);
-    }
-
-    bool isForwarded() const {
-        (void) preserve_; // Suppress warning
-        return magic_ == Relocated;
+        return static_cast<RelocationOverlay*>(cell);
     }
 
     Cell* forwardingAddress() const {
         MOZ_ASSERT(isForwarded());
-        return newLocation_;
+        uintptr_t newLocation = dataWithTag_ & ~Cell::RESERVED_MASK;
+        return reinterpret_cast<Cell*>(newLocation);
     }
 
     void forwardTo(Cell* cell);
 
     RelocationOverlay*& nextRef() {
         MOZ_ASSERT(isForwarded());
         return next_;
     }
 
     RelocationOverlay* next() const {
         MOZ_ASSERT(isForwarded());
         return next_;
     }
-
-    static bool isCellForwarded(const Cell* cell) {
-        return fromCell(cell)->isForwarded();
-    }
 };
 
 } // namespace gc
 } // namespace js
 
 #endif /* gc_RelocationOverlay_h */
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -638,18 +638,17 @@ IsValidGCThingPointer(Cell* cell)
 }
 
 void
 CheckHeapTracer::checkCell(Cell* cell)
 {
     // Moving
     if (!IsValidGCThingPointer(cell) ||
         ((gcType == GCType::Moving) && !IsGCThingValidAfterMovingGC(cell)) ||
-        ((gcType == GCType::NonMoving) &&
-            RelocationOverlay::isCellForwarded(cell)))
+        ((gcType == GCType::NonMoving) && cell->isForwarded()))
     {
         failures++;
         fprintf(stderr, "Bad pointer %p\n", cell);
         dumpCellPath();
     }
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1481032.js
@@ -0,0 +1,6 @@
+x = [];
+x[6] = 0;
+Object.preventExtensions(x);
+
+// Don't assert.
+x.length = 1;
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -5117,15 +5117,16 @@ BaselineCompiler::emit_JSOP_DERIVEDCONST
 }
 
 bool
 BaselineCompiler::emit_JSOP_IMPORTMETA()
 {
     RootedModuleObject module(cx, GetModuleObjectForScript(script));
     MOZ_ASSERT(module);
 
-    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, module);
+    RootedScript moduleScript(cx, module->script());
+    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, moduleScript);
     if (!metaObject)
         return false;
 
     frame.push(ObjectValue(*metaObject));
     return true;
 }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -13575,32 +13575,23 @@ CodeGenerator::visitFinishBoundFunctionI
 
 void
 CodeGenerator::visitIsPackedArray(LIsPackedArray* lir)
 {
     Register array = ToRegister(lir->array());
     Register output = ToRegister(lir->output());
     Register elementsTemp = ToRegister(lir->temp());
 
-    Label notPacked, done;
-
     // Load elements and length.
     masm.loadPtr(Address(array, NativeObject::offsetOfElements()), elementsTemp);
     masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), output);
 
     // Test length == initializedLength.
     Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
-    masm.branch32(Assembler::NotEqual, initLength, output, &notPacked);
-
-    masm.move32(Imm32(1), output);
-    masm.jump(&done);
-    masm.bind(&notPacked);
-    masm.move32(Imm32(0), output);
-
-    masm.bind(&done);
+    masm.cmp32Set(Assembler::Equal, initLength, output, output);
 }
 
 typedef bool (*GetPrototypeOfFn)(JSContext*, HandleObject, MutableHandleValue);
 static const VMFunction GetPrototypeOfInfo =
     FunctionInfo<GetPrototypeOfFn>(jit::GetPrototypeOf, "GetPrototypeOf");
 
 void
 CodeGenerator::visitGetPrototypeOf(LGetPrototypeOf* lir)
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -2421,16 +2421,34 @@ MacroAssemblerARMCompat::cmp32(Register 
 
 void
 MacroAssemblerARMCompat::cmp32(Register lhs, Register rhs)
 {
     ma_cmp(lhs, rhs);
 }
 
 void
+MacroAssemblerARMCompat::cmp32(const Address& lhs, Imm32 rhs)
+{
+    ScratchRegisterScope scratch(asMasm());
+    SecondScratchRegisterScope scratch2(asMasm());
+    ma_ldr(lhs, scratch, scratch2);
+    ma_cmp(scratch, rhs, scratch2);
+}
+
+void
+MacroAssemblerARMCompat::cmp32(const Address& lhs, Register rhs)
+{
+    ScratchRegisterScope scratch(asMasm());
+    SecondScratchRegisterScope scratch2(asMasm());
+    ma_ldr(lhs, scratch, scratch2);
+    ma_cmp(scratch, rhs);
+}
+
+void
 MacroAssemblerARMCompat::cmpPtr(Register lhs, ImmWord rhs)
 {
     cmp32(lhs, Imm32(rhs.value));
 }
 
 void
 MacroAssemblerARMCompat::cmpPtr(Register lhs, ImmPtr rhs)
 {
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1111,22 +1111,18 @@ class MacroAssemblerARMCompat : public M
     void moveDouble(FloatRegister src, FloatRegister dest, Condition cc = Always) {
         ma_vmov(src, dest, cc);
     }
 
     inline void incrementInt32Value(const Address& addr);
 
     void cmp32(Register lhs, Imm32 rhs);
     void cmp32(Register lhs, Register rhs);
-    void cmp32(const Address& lhs, Imm32 rhs) {
-        MOZ_CRASH("NYI");
-    }
-    void cmp32(const Address& lhs, Register rhs) {
-        MOZ_CRASH("NYI");
-    }
+    void cmp32(const Address& lhs, Imm32 rhs);
+    void cmp32(const Address& lhs, Register rhs);
 
     void cmpPtr(Register lhs, Register rhs);
     void cmpPtr(Register lhs, ImmWord rhs);
     void cmpPtr(Register lhs, ImmPtr rhs);
     void cmpPtr(Register lhs, ImmGCPtr rhs);
     void cmpPtr(Register lhs, Imm32 rhs);
     void cmpPtr(const Address& lhs, Register rhs);
     void cmpPtr(const Address& lhs, ImmWord rhs);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1266,16 +1266,25 @@ JS::CurrentGlobalOrNull(JSContext* cx)
 JS_PUBLIC_API(JSObject*)
 JS::GetNonCCWObjectGlobal(JSObject* obj)
 {
     AssertHeapIsIdleOrIterating();
     MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj));
     return &obj->nonCCWGlobal();
 }
 
+JS_PUBLIC_API(JSObject*)
+JS::GetScriptGlobal(JSScript* script)
+{
+    AssertHeapIsIdleOrIterating();
+    JSObject* global = script->realm()->maybeGlobal();
+    MOZ_ASSERT(global);
+    return global;
+}
+
 JS_PUBLIC_API(bool)
 JS::detail::ComputeThis(JSContext* cx, Value* vp, MutableHandleObject thisObject)
 {
     AssertHeapIsIdle();
     assertSameCompartment(cx, vp[0], vp[1]);
 
     MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
     if (!BoxNonStrictThis(cx, thisv, thisv))
@@ -4242,17 +4251,17 @@ JS_PUBLIC_API(bool)
 JS::CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                            JS::SourceBufferHolder& srcBuf,
                            OffThreadCompileCallback callback, void* callbackData)
 {
     MOZ_ASSERT(CanCompileOffThread(cx, options, srcBuf.length()));
     return StartOffThreadParseModule(cx, options, srcBuf, callback, callbackData);
 }
 
-JS_PUBLIC_API(JSObject*)
+JS_PUBLIC_API(JSScript*)
 JS::FinishOffThreadModule(JSContext* cx, JS::OffThreadToken* token)
 {
     MOZ_ASSERT(cx);
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
     return HelperThreadState().finishModuleParseTask(cx, token);
 }
 
 JS_PUBLIC_API(void)
@@ -4833,63 +4842,71 @@ JS_PUBLIC_API(void)
 JS::SetModuleMetadataHook(JSRuntime* rt, JS::ModuleMetadataHook func)
 {
     AssertHeapIsIdle();
     rt->moduleMetadataHook = func;
 }
 
 JS_PUBLIC_API(bool)
 JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
-                  SourceBufferHolder& srcBuf, JS::MutableHandleObject module)
+                  SourceBufferHolder& srcBuf, JS::MutableHandleScript script)
 {
     MOZ_ASSERT(!cx->zone()->isAtomsZone());
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    module.set(frontend::CompileModule(cx, options, srcBuf));
-    return !!module;
+    script.set(frontend::CompileModule(cx, options, srcBuf));
+    return !!script;
 }
 
 JS_PUBLIC_API(void)
-JS::SetModuleHostDefinedField(JSObject* module, const JS::Value& value)
-{
-    module->as<ModuleObject>().setHostDefinedField(value);
+JS::SetModuleHostDefinedField(JSScript* script, const JS::Value& value)
+{
+    MOZ_ASSERT(script->module());
+    script->module()->setHostDefinedField(value);
 }
 
 JS_PUBLIC_API(JS::Value)
-JS::GetModuleHostDefinedField(JSObject* module)
-{
-    return module->as<ModuleObject>().hostDefinedField();
-}
-
-JS_PUBLIC_API(bool)
-JS::ModuleInstantiate(JSContext* cx, JS::HandleObject moduleArg)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, moduleArg);
-    return ModuleObject::Instantiate(cx, moduleArg.as<ModuleObject>());
-}
-
-JS_PUBLIC_API(bool)
-JS::ModuleEvaluate(JSContext* cx, JS::HandleObject moduleArg)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, moduleArg);
-    return ModuleObject::Evaluate(cx, moduleArg.as<ModuleObject>());
+JS::GetModuleHostDefinedField(JSScript* script)
+{
+    MOZ_ASSERT(script->module());
+    return script->module()->hostDefinedField();
+}
+
+JS_PUBLIC_API(bool)
+JS::ModuleInstantiate(JSContext* cx, JS::HandleScript script)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, script);
+    RootedModuleObject module(cx, script->module());
+    MOZ_ASSERT(module);
+    return ModuleObject::Instantiate(cx, module);
+}
+
+JS_PUBLIC_API(bool)
+JS::ModuleEvaluate(JSContext* cx, JS::HandleScript script)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, script);
+    RootedModuleObject module(cx, script->module());
+    MOZ_ASSERT(module);
+    return ModuleObject::Evaluate(cx, module);
 }
 
 JS_PUBLIC_API(JSObject*)
-JS::GetRequestedModules(JSContext* cx, JS::HandleObject moduleArg)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, moduleArg);
-    return &moduleArg->as<ModuleObject>().requestedModules();
+JS::GetRequestedModules(JSContext* cx, JS::HandleScript script)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, script);
+    RootedModuleObject module(cx, script->module());
+    MOZ_ASSERT(module);
+    return &module->requestedModules();
 }
 
 JS_PUBLIC_API(JSString*)
 JS::GetRequestedModuleSpecifier(JSContext* cx, JS::HandleValue value)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value);
@@ -4906,23 +4923,16 @@ JS::GetRequestedModuleSourcePos(JSContex
     assertSameCompartment(cx, value);
     MOZ_ASSERT(lineNumber);
     MOZ_ASSERT(columnNumber);
     auto& requested = value.toObject().as<RequestedModuleObject>();
     *lineNumber = requested.lineNumber();
     *columnNumber = requested.columnNumber();
 }
 
-JS_PUBLIC_API(JSScript*)
-JS::GetModuleScript(JS::HandleObject moduleRecord)
-{
-    AssertHeapIsIdle();
-    return moduleRecord->as<ModuleObject>().script();
-}
-
 JS_PUBLIC_API(JSObject*)
 JS_New(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, ctor, inputArgs);
 
     RootedValue ctorVal(cx, ObjectValue(*ctor));
@@ -7624,28 +7634,21 @@ JS::IsWasmModuleObject(HandleObject obj)
 
 JS_PUBLIC_API(RefPtr<JS::WasmModule>)
 JS::GetWasmModule(HandleObject obj)
 {
     MOZ_ASSERT(JS::IsWasmModuleObject(obj));
     return &CheckedUnwrap(obj)->as<WasmModuleObject>().module();
 }
 
-JS_PUBLIC_API(bool)
-JS::CompiledWasmModuleAssumptionsMatch(PRFileDesc* compiled, JS::BuildIdCharVector&& buildId)
-{
-    return wasm::CompiledModuleAssumptionsMatch(compiled, std::move(buildId));
-}
-
 JS_PUBLIC_API(RefPtr<JS::WasmModule>)
-JS::DeserializeWasmModule(PRFileDesc* bytecode, PRFileDesc* maybeCompiled,
-                          JS::BuildIdCharVector&& buildId, UniqueChars file,
-                          unsigned line)
-{
-    return wasm::DeserializeModule(bytecode, maybeCompiled, std::move(buildId), std::move(file), line);
+JS::DeserializeWasmModule(PRFileDesc* bytecode, JS::BuildIdCharVector&& buildId,
+                          UniqueChars filename, unsigned line)
+{
+    return wasm::DeserializeModule(bytecode, std::move(buildId), std::move(filename), line);
 }
 
 JS_PUBLIC_API(void)
 JS::SetProcessLargeAllocationFailureCallback(JS::LargeAllocationFailureCallback lafc)
 {
     MOZ_ASSERT(!OnLargeAllocationFailure);
     OnLargeAllocationFailure = lafc;
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1229,16 +1229,22 @@ CurrentGlobalOrNull(JSContext* cx);
 /**
  * Get the global object associated with an object's realm. The object must not
  * be a cross-compartment wrapper (because CCWs are shared by all realms in the
  * compartment).
  */
 extern JS_PUBLIC_API(JSObject*)
 GetNonCCWObjectGlobal(JSObject* obj);
 
+/**
+ * Get the global object associated with a script's realm.
+ */
+extern JS_PUBLIC_API(JSObject*)
+GetScriptGlobal(JSScript* script);
+
 } // namespace JS
 
 /**
  * Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the
  * given global.
  */
 extern JS_PUBLIC_API(bool)
 JS_InitReflectParse(JSContext* cx, JS::HandleObject global);
@@ -3687,17 +3693,17 @@ FinishOffThreadScript(JSContext* cx, Off
 extern JS_PUBLIC_API(void)
 CancelOffThreadScript(JSContext* cx, OffThreadToken* token);
 
 extern JS_PUBLIC_API(bool)
 CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                        JS::SourceBufferHolder& srcBuf,
                        OffThreadCompileCallback callback, void* callbackData);
 
-extern JS_PUBLIC_API(JSObject*)
+extern JS_PUBLIC_API(JSScript*)
 FinishOffThreadModule(JSContext* cx, OffThreadToken* token);
 
 extern JS_PUBLIC_API(void)
 CancelOffThreadModule(JSContext* cx, OffThreadToken* token);
 
 extern JS_PUBLIC_API(bool)
 DecodeOffThreadScript(JSContext* cx, const ReadOnlyCompileOptions& options,
                       mozilla::Vector<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,
@@ -3859,88 +3865,88 @@ Evaluate(JSContext* cx, const ReadOnlyCo
 
 /**
  * Evaluate the given file in the scope of the current global of cx.
  */
 extern JS_PUBLIC_API(bool)
 Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
          const char* filename, JS::MutableHandleValue rval);
 
-using ModuleResolveHook = JSObject* (*)(JSContext*, HandleObject, HandleString);
+using ModuleResolveHook = JSScript* (*)(JSContext*, HandleScript, HandleString);
 
 /**
  * Get the HostResolveImportedModule hook for the runtime.
  */
 extern JS_PUBLIC_API(ModuleResolveHook)
 GetModuleResolveHook(JSRuntime* rt);
 
 /**
  * Set the HostResolveImportedModule hook for the runtime to the given function.
  */
 extern JS_PUBLIC_API(void)
 SetModuleResolveHook(JSRuntime* rt, ModuleResolveHook func);
 
-using ModuleMetadataHook = bool (*)(JSContext*, HandleObject, HandleObject);
+using ModuleMetadataHook = bool (*)(JSContext*, HandleScript, HandleObject);
 
 /**
  * Get the hook for populating the import.meta metadata object.
  */
 extern JS_PUBLIC_API(ModuleMetadataHook)
 GetModuleMetadataHook(JSRuntime* rt);
 
 /**
  * Set the hook for populating the import.meta metadata object to the given
  * function.
  */
 extern JS_PUBLIC_API(void)
 SetModuleMetadataHook(JSRuntime* rt, ModuleMetadataHook func);
 
 /**
  * Parse the given source buffer as a module in the scope of the current global
- * of cx and return a source text module record.
+ * of cx.
  */
 extern JS_PUBLIC_API(bool)
 CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
-              SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord);
+              SourceBufferHolder& srcBuf, JS::MutableHandleScript script);
 
 /**
  * Set the [[HostDefined]] field of a source text module record to the given
  * value.
  */
 extern JS_PUBLIC_API(void)
-SetModuleHostDefinedField(JSObject* module, const JS::Value& value);
+SetModuleHostDefinedField(JSScript* module, const JS::Value& value);
 
 /**
  * Get the [[HostDefined]] field of a source text module record.
  */
 extern JS_PUBLIC_API(JS::Value)
-GetModuleHostDefinedField(JSObject* module);
+GetModuleHostDefinedField(JSScript* script);
 
 /*
  * Perform the ModuleInstantiate operation on the given source text module
  * record.
  *
  * This transitively resolves all module dependencies (calling the
  * HostResolveImportedModule hook) and initializes the environment record for
  * the module.
  */
 extern JS_PUBLIC_API(bool)
-ModuleInstantiate(JSContext* cx, JS::HandleObject moduleRecord);
+ModuleInstantiate(JSContext* cx, JS::HandleScript script);
 
 /*
  * Perform the ModuleEvaluate operation on the given source text module record.
  *
  * This does nothing if this module has already been evaluated. Otherwise, it
  * transitively evaluates all dependences of this module and then evaluates this
  * module.
  *
  * ModuleInstantiate must have completed prior to calling this.
  */
 extern JS_PUBLIC_API(bool)
-ModuleEvaluate(JSContext* cx, JS::HandleObject moduleRecord);
+ModuleEvaluate(JSContext* cx, JS::HandleScript script);
 
 /*
  * Get a list of the module specifiers used by a source text module
  * record to request importation of modules.
  *
  * The result is a JavaScript array of object values.  To extract the individual
  * values use only JS_GetArrayLength and JS_GetElement with indices 0 to length
  * - 1.
@@ -3949,28 +3955,25 @@ ModuleEvaluate(JSContext* cx, JS::Handle
  *  - moduleSpecifier: the module specifier string
  *  - lineNumber: the line number of the import in the source text
  *  - columnNumber: the column number of the import in the source text
  *
  * These property values can be extracted with GetRequestedModuleSpecifier() and
  * GetRequestedModuleSourcePos()
  */
 extern JS_PUBLIC_API(JSObject*)
-GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord);
+GetRequestedModules(JSContext* cx, JS::HandleScript script);
 
 extern JS_PUBLIC_API(JSString*)
 GetRequestedModuleSpecifier(JSContext* cx, JS::HandleValue requestedModuleObject);
 
 extern JS_PUBLIC_API(void)
 GetRequestedModuleSourcePos(JSContext* cx, JS::HandleValue requestedModuleObject,
                             uint32_t* lineNumber, uint32_t* columnNumber);
 
-extern JS_PUBLIC_API(JSScript*)
-GetModuleScript(JS::HandleObject moduleRecord);
-
 } /* namespace JS */
 
 #if defined(JS_BUILD_BINAST)
 
 namespace JS {
 
 extern JS_PUBLIC_API(JSScript*)
 DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
@@ -5971,39 +5974,16 @@ SetBuildIdOp(JSContext* cx, BuildIdOp bu
  *
  * - GetWasmModule() is called when making a structured clone of payload
  * containing a WebAssembly.Module object. The structured clone buffer holds a
  * refcount of the JS::WasmModule until createObject() is called in the target
  * agent's JSContext. The new WebAssembly.Module object continues to hold the
  * JS::WasmModule and thus the final reference of a JS::WasmModule may be
  * dropped from any thread and so the virtual destructor (and all internal
  * methods of the C++ module) must be thread-safe.
- *
- * For (de)serialization:
- *
- * - Serialization starts when WebAssembly.Module is passed to the
- * structured-clone algorithm. JS::GetWasmModule is called on the JSRuntime
- * thread that initiated the structured clone to get the JS::WasmModule.
- * This interface is then taken to a background thread where the bytecode and
- * compiled code are written into separate files: a bytecode file that always
- * allows successful deserialization and a compiled-code file keyed on cpu- and
- * build-id that may become invalid if either of these change between
- * serialization and deserialization. Due to tiering, the serialization must
- * asynchronously wait for compilation to complete before requesting the
- * module's compiled code. After serialization, a reference is dropped from a
- * separate thread so the virtual destructor must be thread-safe.
- *
- * - Deserialization starts when the structured clone algorithm encounters a
- * serialized WebAssembly.Module. On a background thread, the compiled-code file
- * is opened and CompiledWasmModuleAssumptionsMatch is called to see if it is
- * still valid (as described above). DeserializeWasmModule is then called to
- * construct a JS::WasmModule (also on the background thread), passing the
- * bytecode file descriptor and, if valid, the compiled-code file descriptor.
- * The JS::WasmObject is then transported to a JSContext thread and the wrapping
- * WebAssembly.Module object is created by calling createObject().
  */
 
 class WasmModuleListener
 {
   protected:
     virtual ~WasmModuleListener() {}
 
   public:
@@ -6015,43 +5995,27 @@ class WasmModuleListener
     virtual MozExternalRefCountType MOZ_XPCOM_ABI Release() = 0;
 
     virtual void onCompilationComplete() = 0;
 };
 
 struct WasmModule : js::AtomicRefCounted<WasmModule>
 {
     virtual ~WasmModule() {}
-
-    virtual size_t bytecodeSerializedSize() const = 0;
-    virtual void bytecodeSerialize(uint8_t* bytecodeBegin, size_t bytecodeSize) const = 0;
-
-    // Compilation must complete before the serialized code is requested. If
-    // compilation is not complete, the embedding must wait until notified by
-    // implementing WasmModuleListener. SpiderMonkey will hold a RefPtr to
-    // 'listener' until onCompilationComplete() is called.
-    virtual bool compilationComplete() const = 0;
-    virtual bool notifyWhenCompilationComplete(WasmModuleListener* listener) = 0;
-    virtual size_t compiledSerializedSize() const = 0;
-    virtual void compiledSerialize(uint8_t* compiledBegin, size_t compiledSize) const = 0;
-
     virtual JSObject* createObject(JSContext* cx) = 0;
 };
 
 extern JS_PUBLIC_API(bool)
 IsWasmModuleObject(HandleObject obj);
 
 extern JS_PUBLIC_API(RefPtr<WasmModule>)
 GetWasmModule(HandleObject obj);
 
-extern JS_PUBLIC_API(bool)
-CompiledWasmModuleAssumptionsMatch(PRFileDesc* compiled, BuildIdCharVector&& buildId);
-
 extern JS_PUBLIC_API(RefPtr<WasmModule>)
-DeserializeWasmModule(PRFileDesc* bytecode, PRFileDesc* maybeCompiled, BuildIdCharVector&& buildId,
+DeserializeWasmModule(PRFileDesc* bytecode, BuildIdCharVector&& buildId,
                       JS::UniqueChars filename, unsigned line);
 
 /**
  * Convenience class for imitating a JS level for-of loop. Typical usage:
  *
  *     ForOfIterator it(cx);
  *     if (!it.init(iterable))
  *       return false;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -790,77 +790,77 @@ GetObjectSlot(JSObject* obj, size_t slot
 {
     MOZ_ASSERT(slot < GetObjectSlotSpan(obj));
     return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot);
 }
 
 MOZ_ALWAYS_INLINE size_t
 GetAtomLength(JSAtom* atom)
 {
-    return reinterpret_cast<JS::shadow::String*>(atom)->length;
+    return reinterpret_cast<JS::shadow::String*>(atom)->length();
 }
 
 static const uint32_t MaxStringLength = (1 << 28) - 1;
 
 MOZ_ALWAYS_INLINE size_t
 GetStringLength(JSString* s)
 {
-    return reinterpret_cast<JS::shadow::String*>(s)->length;
+    return reinterpret_cast<JS::shadow::String*>(s)->length();
 }
 
 MOZ_ALWAYS_INLINE size_t
 GetFlatStringLength(JSFlatString* s)
 {
-    return reinterpret_cast<JS::shadow::String*>(s)->length;
+    return reinterpret_cast<JS::shadow::String*>(s)->length();
 }
 
 MOZ_ALWAYS_INLINE size_t
 GetLinearStringLength(JSLinearString* s)
 {
-    return reinterpret_cast<JS::shadow::String*>(s)->length;
+    return reinterpret_cast<JS::shadow::String*>(s)->length();
 }
 
 MOZ_ALWAYS_INLINE bool
 LinearStringHasLatin1Chars(JSLinearString* s)
 {
-    return reinterpret_cast<JS::shadow::String*>(s)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
+    return reinterpret_cast<JS::shadow::String*>(s)->flags() & JS::shadow::String::LATIN1_CHARS_BIT;
 }
 
 MOZ_ALWAYS_INLINE bool
 AtomHasLatin1Chars(JSAtom* atom)
 {
-    return reinterpret_cast<JS::shadow::String*>(atom)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
+    return reinterpret_cast<JS::shadow::String*>(atom)->flags() & JS::shadow::String::LATIN1_CHARS_BIT;
 }
 
 MOZ_ALWAYS_INLINE bool
 StringHasLatin1Chars(JSString* s)
 {
-    return reinterpret_cast<JS::shadow::String*>(s)->flags & JS::shadow::String::LATIN1_CHARS_BIT;
+    return reinterpret_cast<JS::shadow::String*>(s)->flags() & JS::shadow::String::LATIN1_CHARS_BIT;
 }
 
 MOZ_ALWAYS_INLINE const JS::Latin1Char*
 GetLatin1LinearStringChars(const JS::AutoRequireNoGC& nogc, JSLinearString* linear)
 {
     MOZ_ASSERT(LinearStringHasLatin1Chars(linear));
 
     using JS::shadow::String;
     String* s = reinterpret_cast<String*>(linear);
-    if (s->flags & String::INLINE_CHARS_BIT)
+    if (s->flags() & String::INLINE_CHARS_BIT)
         return s->inlineStorageLatin1;
     return s->nonInlineCharsLatin1;
 }
 
 MOZ_ALWAYS_INLINE const char16_t*
 GetTwoByteLinearStringChars(const JS::AutoRequireNoGC& nogc, JSLinearString* linear)
 {
     MOZ_ASSERT(!LinearStringHasLatin1Chars(linear));
 
     using JS::shadow::String;
     String* s = reinterpret_cast<String*>(linear);
-    if (s->flags & String::INLINE_CHARS_BIT)
+    if (s->flags() & String::INLINE_CHARS_BIT)
         return s->inlineStorageTwoByte;
     return s->nonInlineCharsTwoByte;
 }
 
 MOZ_ALWAYS_INLINE JSLinearString*
 AtomToLinearString(JSAtom* atom)
 {
     return reinterpret_cast<JSLinearString*>(atom);
@@ -891,34 +891,34 @@ GetTwoByteAtomChars(const JS::AutoRequir
 }
 
 MOZ_ALWAYS_INLINE bool
 IsExternalString(JSString* str, const JSStringFinalizer** fin, const char16_t** chars)
 {
     using JS::shadow::String;
     String* s = reinterpret_cast<String*>(str);
 
-    if ((s->flags & String::TYPE_FLAGS_MASK) != String::EXTERNAL_FLAGS)
+    if ((s->flags() & String::TYPE_FLAGS_MASK) != String::EXTERNAL_FLAGS)
         return false;
 
     MOZ_ASSERT(JS_IsExternalString(str));
     *fin = s->externalFinalizer;
     *chars = s->nonInlineCharsTwoByte;
     return true;
 }
 
 JS_FRIEND_API(JSLinearString*)
 StringToLinearStringSlow(JSContext* cx, JSString* str);
 
 MOZ_ALWAYS_INLINE JSLinearString*
 StringToLinearString(JSContext* cx, JSString* str)
 {
     using JS::shadow::String;
     String* s = reinterpret_cast<String*>(str);
-    if (MOZ_UNLIKELY(!(s->flags & String::LINEAR_BIT)))
+    if (MOZ_UNLIKELY(!(s->flags() & String::LINEAR_BIT)))
         return StringToLinearStringSlow(cx, str);
     return reinterpret_cast<JSLinearString*>(str);
 }
 
 template<typename CharType>
 MOZ_ALWAYS_INLINE void
 CopyLinearStringChars(CharType* dest, JSLinearString* s, size_t len, size_t start = 0);
 
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -847,16 +847,22 @@ case "$target" in
     	AC_DEFINE(_X86_)
 	;;
     x86_64-*)
         if test -n "$_WIN32_MSVC"; then
             DSO_LDOPTS="$DSO_LDOPTS -MACHINE:X64"
         fi
         AC_DEFINE(_AMD64_)
         ;;
+    aarch64-*)
+        if test -n "$_WIN32_MSVC"; then
+            DSO_LDOPTS="$DSO_LDOPTS -MACHINE:ARM64"
+        fi
+        AC_DEFINE(_ARM64_)
+        ;;
     *)
     	AC_DEFINE(_CPU_ARCH_NOT_DEFINED)
 	;;
     esac
     ;;
 
 *-netbsd*)
     DSO_CFLAGS=''
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4294,21 +4294,21 @@ ParseModule(JSContext* cx, unsigned argc
     AutoStableStringChars stableChars(cx);
     if (!stableChars.initTwoByte(cx, scriptContents))
         return false;
 
     const char16_t* chars = stableChars.twoByteRange().begin().get();
     SourceBufferHolder srcBuf(chars, scriptContents->length(),
                               SourceBufferHolder::NoOwnership);
 
-    RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf));
-    if (!module)
-        return false;
-
-    args.rval().setObject(*module);
+    RootedScript script(cx, frontend::CompileModule(cx, options, srcBuf));
+    if (!script)
+        return false;
+
+    args.rval().setObject(*script->module());
     return true;
 }
 
 static bool
 SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
@@ -4325,48 +4325,49 @@ SetModuleResolveHook(JSContext* cx, unsi
 
     Handle<GlobalObject*> global = cx->global();
     global->setReservedSlot(GlobalAppSlotModuleResolveHook, args[0]);
 
     args.rval().setUndefined();
     return true;
 }
 
-static JSObject*
-CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier)
-{
+static JSScript*
+CallModuleResolveHook(JSContext* cx, HandleScript script, HandleString specifier)
+{
+    MOZ_ASSERT(script->module());
+
     Handle<GlobalObject*> global = cx->global();
     RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleResolveHook));
     if (hookValue.isUndefined()) {
         JS_ReportErrorASCII(cx, "Module resolve hook not set");
         return nullptr;
     }
     MOZ_ASSERT(hookValue.toObject().is<JSFunction>());
 
     JS::AutoValueArray<2> args(cx);
-    args[0].setObject(*module);
+    args[0].setObject(*script->module());
     args[1].setString(specifier);
 
     RootedValue result(cx);
     if (!JS_CallFunctionValue(cx, nullptr, hookValue, args, &result))
         return nullptr;
 
     if (!result.isObject() || !result.toObject().is<ModuleObject>()) {
          JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
          return nullptr;
     }
 
-    return &result.toObject();
-}
-
-static bool
-ShellModuleMetadataHook(JSContext* cx, HandleObject module, HandleObject metaObject)
+    return result.toObject().as<ModuleObject>().script();
+}
+
+static bool
+ShellModuleMetadataHook(JSContext* cx, HandleScript script, HandleObject metaObject)
 {
     // For the shell, just use the script's filename as the base URL.
-    RootedScript script(cx, module->as<ModuleObject>().script());
     const char* filename = script->scriptSource()->filename();
     MOZ_ASSERT(filename);
 
     RootedString url(cx, NewStringCopyZ<CanGC>(cx, filename));
     if (!url)
         return false;
 
     if (!JS_DefineProperty(cx, metaObject, "url", url, JSPROP_ENUMERATE))
@@ -4858,21 +4859,21 @@ FinishOffThreadModule(JSContext* cx, uns
     if (!job)
         return false;
 
     JS::OffThreadToken* token = job->waitUntilDone(cx);
     MOZ_ASSERT(token);
 
     DeleteOffThreadJob(cx, job);
 
-    RootedObject module(cx, JS::FinishOffThreadModule(cx, token));
-    if (!module)
-        return false;
-
-    args.rval().setObject(*module);
+    RootedScript script(cx, JS::FinishOffThreadModule(cx, token));
+    if (!script)
+        return false;
+
+    args.rval().setObject(*script->module());
     return true;
 }
 
 static bool
 OffThreadDecodeScript(JSContext* cx, unsigned argc, Value* vp)
 {
     if (!CanUseExtraThreads()) {
         JS_ReportErrorASCII(cx, "Can't use offThreadDecodeScript with --no-threads");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/generators/yield-star-throw-htmldda.js
@@ -0,0 +1,28 @@
+function* g(iter) {
+    yield* iter;
+}
+
+var calledReturn = false;
+
+var it = g({
+    [Symbol.iterator]() {
+        return this;
+    },
+    next() {
+        return {done: false};
+    },
+    throw: createIsHTMLDDA(),
+    return() {
+        calledReturn = true;
+        return {done: false};
+    }
+});
+
+it.next();
+
+assertThrowsInstanceOf(() => it.throw(""), TypeError);
+
+assertEq(calledReturn, false);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
--- a/js/src/vm/BigIntType.h
+++ b/js/src/vm/BigIntType.h
@@ -33,23 +33,26 @@ namespace JS {
 
 class BigInt final : public js::gc::TenuredCell
 {
     // StringToBigIntImpl modifies the num_ field of the res argument.
     template <typename CharT>
     friend bool js::StringToBigIntImpl(const mozilla::Range<const CharT>& chars,
                                        uint8_t radix, Handle<BigInt*> res);
 
+  protected:
+    // Reserved word for Cell GC invariants. This also ensures minimum
+    // structure size.
+    uintptr_t reserved_;
+
   private:
-    // The minimum allocation size is currently 16 bytes (see
-    // SortedArenaList in gc/ArenaList.h).
-    union {
-        mpz_t num_;
-        uint8_t unused_[js::gc::MinCellSize];
-    };
+    mpz_t num_;
+
+  protected:
+    BigInt() : reserved_(0) { }
 
   public:
     // Allocate and initialize a BigInt value
     static BigInt* create(JSContext* cx);
 
     static BigInt* createFromDouble(JSContext* cx, double d);
 
     static BigInt* createFromBoolean(JSContext* cx, bool b);
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -520,19 +520,19 @@ ModuleParseTask::ModuleParseTask(JSConte
     data(std::move(srcBuf))
 {}
 
 void
 ModuleParseTask::parse(JSContext* cx)
 {
     Rooted<ScriptSourceObject*> sourceObject(cx);
 
-    ModuleObject* module = frontend::CompileModule(cx, options, data, alloc, &sourceObject.get());
-    if (module) {
-        scripts.infallibleAppend(module->script());
+    JSScript* script = frontend::CompileModule(cx, options, data, alloc, &sourceObject.get());
+    if (script) {
+        scripts.infallibleAppend(script);
         if (sourceObject)
             sourceObjects.infallibleAppend(sourceObject);
     }
 }
 
 ScriptDecodeTask::ScriptDecodeTask(JSContext* cx, const JS::TranscodeRange& range,
                                    JS::OffThreadCompileCallback callback, void* callbackData)
   : ParseTask(ParseTaskKind::ScriptDecode, cx, callback, callbackData),
@@ -1801,31 +1801,31 @@ GlobalHelperThreadState::finishBinASTDec
 
 bool
 GlobalHelperThreadState::finishMultiScriptsDecodeTask(JSContext* cx, JS::OffThreadToken* token,
                                                       MutableHandle<ScriptVector> scripts)
 {
     return finishParseTask(cx, ParseTaskKind::MultiScriptsDecode, token, scripts);
 }
 
-JSObject*
+JSScript*
 GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token)
 {
-    JSScript* script = finishParseTask(cx, ParseTaskKind::Module, token);
+    RootedScript script(cx, finishParseTask(cx, ParseTaskKind::Module, token));
     if (!script)
         return nullptr;
 
     MOZ_ASSERT(script->module());
 
     RootedModuleObject module(cx, script->module());
     module->fixEnvironmentsAfterCompartmentMerge();
     if (!ModuleObject::Freeze(cx, module))
         return nullptr;
 
-    return module;
+    return script;
 }
 
 void
 GlobalHelperThreadState::cancelParseTask(JSRuntime* rt, ParseTaskKind kind,
                                          JS::OffThreadToken* token)
 {
     destroyParseTask(rt, removeFinishedParseTask(kind, token));
 }
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -301,17 +301,17 @@ class GlobalHelperThreadState
 
     void mergeParseTaskRealm(JSContext* cx, ParseTask* parseTask, JS::Realm* dest);
 
     void trace(JSTracer* trc);
 
     JSScript* finishScriptParseTask(JSContext* cx, JS::OffThreadToken* token);
     JSScript* finishScriptDecodeTask(JSContext* cx, JS::OffThreadToken* token);
     bool finishMultiScriptsDecodeTask(JSContext* cx, JS::OffThreadToken* token, MutableHandle<ScriptVector> scripts);
-    JSObject* finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token);
+    JSScript* finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token);
 
 #if defined(JS_BUILD_BINAST)
     JSScript* finishBinASTDecodeTask(JSContext* cx, JS::OffThreadToken* token);
 #endif
 
     bool hasActiveThreads(const AutoLockHelperThreadState&);
     void waitForAllThreads();
     void waitForAllThreadsLocked(AutoLockHelperThreadState&);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4391,17 +4391,18 @@ CASE(JSOP_NEWTARGET)
     MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
 END_CASE(JSOP_NEWTARGET)
 
 CASE(JSOP_IMPORTMETA)
 {
     ReservedRooted<JSObject*> module(&rootObject0, GetModuleObjectForScript(script));
     MOZ_ASSERT(module);
 
-    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, module);
+    ReservedRooted<JSScript*> script(&rootScript0, module->as<ModuleObject>().script());
+    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, script);
     if (!metaObject)
         goto error;
 
     PUSH_OBJECT(*metaObject);
 }
 END_CASE(JSOP_NEWTARGET)
 
 CASE(JSOP_SUPERFUN)
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -206,16 +206,23 @@ inline bool
 js::IsExtensible(JSContext* cx, HandleObject obj, bool* extensible)
 {
     if (obj->is<ProxyObject>()) {
         MOZ_ASSERT(!cx->helperThread());
         return Proxy::isExtensible(cx, obj, extensible);
     }
 
     *extensible = obj->nonProxyIsExtensible();
+
+    // If the following assertion fails, there's somewhere else a missing
+    // call to shrinkCapacityToInitializedLength() which needs to be found and
+    // fixed.
+    MOZ_ASSERT_IF(obj->isNative() && !*extensible,
+                  obj->as<NativeObject>().getDenseInitializedLength() ==
+                  obj->as<NativeObject>().getDenseCapacity());
     return true;
 }
 
 inline bool
 js::HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* found)
 {
     RootedId id(cx, NameToId(name));
     return HasProperty(cx, obj, id, found);
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -2732,18 +2732,26 @@ js::SetPrototype(JSContext* cx, HandleOb
 }
 
 bool
 js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result)
 {
     if (obj->is<ProxyObject>())
         return js::Proxy::preventExtensions(cx, obj, result);
 
-    if (!obj->nonProxyIsExtensible())
+    if (!obj->nonProxyIsExtensible()) {
+        // If the following assertion fails, there's somewhere else a missing
+        // call to shrinkCapacityToInitializedLength() which needs to be found
+        // and fixed.
+        MOZ_ASSERT_IF(obj->isNative(),
+                      obj->as<NativeObject>().getDenseInitializedLength() ==
+                      obj->as<NativeObject>().getDenseCapacity());
+
         return result.succeed();
+    }
 
     if (!MaybeConvertUnboxedObjectToNative(cx, obj))
         return false;
 
     if (obj->isNative()) {
         // Force lazy properties to be resolved.
         if (!ResolveLazyProperties(cx, obj.as<NativeObject>()))
             return false;
--- a/js/src/vm/MutexIDs.h
+++ b/js/src/vm/MutexIDs.h
@@ -45,17 +45,16 @@
   _(IcuTimeZoneStateMutex,       500) \
   _(ProcessExecutableRegion,     500) \
   _(OffThreadPromiseState,       500) \
   _(BufferStreamState,           500) \
   _(SharedArrayGrow,             500) \
   _(RuntimeScriptData,           500) \
   _(WasmFuncTypeIdSet,           500) \
   _(WasmCodeProfilingLabels,     500) \
-  _(WasmModuleTieringLock,       500) \
   _(WasmCompileTaskState,        500) \
   _(WasmCodeStreamEnd,           500) \
   _(WasmTailBytesPtr,            500) \
   _(WasmStreamStatus,            500) \
   _(WasmRuntimeInstances,        500) \
                                       \
   _(ThreadId,                    600) \
   _(WasmCodeSegmentMap,          600) \
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -964,17 +964,17 @@ NativeObject::growElements(JSContext* cx
 
     return true;
 }
 
 void
 NativeObject::shrinkElements(JSContext* cx, uint32_t reqCapacity)
 {
     MOZ_ASSERT(canHaveNonEmptyElements());
-    MOZ_ASSERT(reqCapacity >= getDenseInitializedLengthUnchecked());
+    MOZ_ASSERT(reqCapacity >= getDenseInitializedLength());
 
     if (denseElementsAreCopyOnWrite())
         MOZ_CRASH();
 
     if (!hasDynamicElements())
         return;
 
     // If we have shifted elements, consider moving them.
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -525,30 +525,17 @@ class NativeObject : public ShapedObject
     }
     const Value& getDenseElement(uint32_t idx) const {
         MOZ_ASSERT(idx < getDenseInitializedLength());
         return elements_[idx];
     }
     bool containsDenseElement(uint32_t idx) {
         return idx < getDenseInitializedLength() && !elements_[idx].isMagic(JS_ELEMENTS_HOLE);
     }
-
-  private:
-    uint32_t getDenseInitializedLengthUnchecked() const {
-        return getElementsHeader()->initializedLength;
-    }
-
-  public:
     uint32_t getDenseInitializedLength() const {
-        // If the following assertion fails, there's somewhere else a missing
-        // call to shrinkCapacityToInitializedLength(). Good luck for the hunt
-        // and finding the offender!
-        MOZ_ASSERT_IF(!isExtensible(),
-                      getElementsHeader()->initializedLength == getElementsHeader()->capacity);
-
         return getElementsHeader()->initializedLength;
     }
     uint32_t getDenseCapacity() const {
         return getElementsHeader()->capacity;
     }
 
     bool isSharedMemory() const {
         return getElementsHeader()->isSharedMemory();
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -1016,16 +1016,22 @@ JS::GetCurrentRealmOrNull(JSContext* cx)
 }
 
 JS_PUBLIC_API(JS::Realm*)
 JS::GetObjectRealmOrNull(JSObject* obj)
 {
     return IsCrossCompartmentWrapper(obj) ? nullptr : obj->nonCCWRealm();
 }
 
+JS_PUBLIC_API(JS::Realm*)
+JS::GetScriptRealm(JSScript* script)
+{
+    return script->realm();
+}
+
 JS_PUBLIC_API(void*)
 JS::GetRealmPrivate(JS::Realm* realm)
 {
     return realm->realmPrivate();
 }
 
 JS_PUBLIC_API(void)
 JS::SetRealmPrivate(JS::Realm* realm, void* data)
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -430,26 +430,26 @@ Scope::clone(JSContext* cx, HandleScope 
 
 void
 Scope::finalize(FreeOp* fop)
 {
     MOZ_ASSERT(CurrentThreadIsGCSweeping());
     if (data_) {
         // We don't need to call the destructors for any GCPtrs in Data because
         // this only happens during a GC.
-        fop->free_(reinterpret_cast<void*>(data_));
-        data_ = 0;
+        fop->free_(data_);
+        data_ = nullptr;
     }
 }
 
 size_t
 Scope::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
     if (data_)
-        return mallocSizeOf(reinterpret_cast<void*>(data_));
+        return mallocSizeOf(data_);
     return 0;
 }
 
 void
 Scope::dump()
 {
     for (ScopeIter si(this); si; si++) {
         fprintf(stderr, "%s [%p]", ScopeKindString(si.kind()), si.scope());
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -21,16 +21,17 @@
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/JSObject.h"
 #include "vm/Xdr.h"
 
 namespace js {
 
+class BaseScopeData;
 class ModuleObject;
 class Scope;
 
 enum class BindingKind : uint8_t
 {
     Import,
     FormalParameter,
     Var,
@@ -299,44 +300,34 @@ class WrappedPtrOperations<Scope*, Wrapp
 
 //
 // The base class of all Scopes.
 //
 class Scope : public js::gc::TenuredCell
 {
     friend class GCMarker;
 
-    // The kind determines data_.
-    //
-    // The memory here must be fully initialized, since otherwise the magic_
-    // value for gc::RelocationOverlay will land in the padding and may be
-    // stale.
-    union {
-        ScopeKind kind_;
-        uintptr_t paddedKind_;
-    };
-
     // The enclosing scope or nullptr.
     GCPtrScope enclosing_;
 
+    // The kind determines data_.
+    ScopeKind kind_;
+
     // If there are any aliased bindings, the shape for the
     // EnvironmentObject. Otherwise nullptr.
     GCPtrShape environmentShape_;
 
   protected:
-    uintptr_t data_;
+    BaseScopeData* data_;
 
     Scope(ScopeKind kind, Scope* enclosing, Shape* environmentShape)
       : enclosing_(enclosing),
+        kind_(kind),
         environmentShape_(environmentShape),
-        data_(0)
-    {
-        paddedKind_ = 0;
-        kind_ = kind;
-    }
+        data_(nullptr) { }
 
     static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
                          HandleShape envShape);
 
     template <typename T, typename D>
     static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
                          HandleShape envShape, mozilla::UniquePtr<T, D> data);
 
@@ -344,17 +335,17 @@ class Scope : public js::gc::TenuredCell
     static XDRResult XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
                                           MutableHandle<typename ConcreteScope::Data*> data);
 
     Shape* maybeCloneEnvironmentShape(JSContext* cx);
 
     template <typename T, typename D>
     void initData(mozilla::UniquePtr<T, D> data) {
         MOZ_ASSERT(!data_);
-        data_ = reinterpret_cast<uintptr_t>(data.release());
+        data_ = data.release();
     }
 
   public:
     static const JS::TraceKind TraceKind = JS::TraceKind::Scope;
 
     template <typename T>
     bool is() const {
         return kind_ == T::classScopeKind_;
@@ -464,17 +455,17 @@ SizeOfData(uint32_t numBindings)
 class LexicalScope : public Scope
 {
     friend class Scope;
     friend class BindingIter;
 
   public:
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newLexicalScopeData.
-    struct Data : BaseScopeData
+    struct Data : public BaseScopeData
     {
         // Bindings are sorted by kind in both frames and environments.
         //
         //   lets - [0, constStart)
         // consts - [constStart, length)
         uint32_t constStart = 0;
         uint32_t length = 0;
 
@@ -500,21 +491,21 @@ class LexicalScope : public Scope
                     MutableHandleScope scope);
 
   private:
     static LexicalScope* createWithData(JSContext* cx, ScopeKind kind,
                                         MutableHandle<UniquePtr<Data>> data,
                                         uint32_t firstFrameSlot, HandleScope enclosing);
 
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     static uint32_t nextFrameSlot(Scope* start);
 
   public:
     uint32_t firstFrameSlot() const;
 
     uint32_t nextFrameSlot() const {
@@ -561,17 +552,17 @@ class FunctionScope : public Scope
     friend class BindingIter;
     friend class PositionalFormalParameterIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::Function;
 
   public:
     // Data is public because it is created by the
     // frontend. See Parser<FullParseHandler>::newFunctionScopeData.
-    struct Data : BaseScopeData
+    struct Data : public BaseScopeData
     {
         // The canonical function of the scope, as during a scope walk we
         // often query properties of the JSFunction (e.g., is the function an
         // arrow).
         GCPtrFunction canonicalFunction = {};
 
         // If parameter expressions are present, parameters act like lexical
         // bindings.
@@ -635,21 +626,21 @@ class FunctionScope : public Scope
                     MutableHandleScope scope);
 
   private:
     static FunctionScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
                                          bool hasParameterExprs, bool needsEnvironment,
                                          HandleFunction fun, HandleScope enclosing);
 
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
   public:
     uint32_t nextFrameSlot() const {
         return data().nextFrameSlot;
     }
 
     JSFunction* canonicalFunction() const {
@@ -694,17 +685,17 @@ class VarScope : public Scope
 {
     friend class GCMarker;
     friend class BindingIter;
     friend class Scope;
 
   public:
     // Data is public because it is created by the
     // frontend. See Parser<FullParseHandler>::newVarScopeData.
-    struct Data : BaseScopeData
+    struct Data : public BaseScopeData
     {
         // All bindings are vars.
         uint32_t length = 0;
 
         // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is
         // the innermost scope.
         uint32_t nextFrameSlot = 0;
 
@@ -727,21 +718,21 @@ class VarScope : public Scope
                     MutableHandleScope scope);
 
   private:
     static VarScope* createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
                                     uint32_t firstFrameSlot, bool needsEnvironment,
                                     HandleScope enclosing);
 
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
   public:
     uint32_t firstFrameSlot() const;
 
     uint32_t nextFrameSlot() const {
         return data().nextFrameSlot;
     }
@@ -817,21 +808,21 @@ class GlobalScope : public Scope
     template <XDRMode mode>
     static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope);
 
   private:
     static GlobalScope* createWithData(JSContext* cx, ScopeKind kind,
                                        MutableHandle<UniquePtr<Data>> data);
 
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
   public:
     bool isSyntactic() const {
         return kind() != ScopeKind::NonSyntactic;
     }
 
     bool hasBindings() const {
@@ -874,17 +865,17 @@ class WithScope : public Scope
 class EvalScope : public Scope
 {
     friend class Scope;
     friend class BindingIter;
 
   public:
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newEvalScopeData.
-    struct Data : BaseScopeData
+    struct Data : public BaseScopeData
     {
         // All bindings in an eval script are 'var' bindings. The implicit
         // lexical scope around the eval is present regardless of strictness
         // and is its own LexicalScope.
         // `vars` includes top-level functions which is distinguished by a bit
         // on the BindingName.
         //
         //            vars - [0, length)
@@ -912,21 +903,21 @@ class EvalScope : public Scope
     static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                     MutableHandleScope scope);
 
   private:
     static EvalScope* createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
                                      HandleScope enclosing);
 
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
   public:
     // Starting a scope, the nearest var scope that a direct eval can
     // introduce vars on.
     static Scope* nearestVarScopeForDirectEval(Scope* scope);
 
     uint32_t nextFrameSlot() const {
@@ -1009,21 +1000,21 @@ class ModuleScope : public Scope
     static ModuleScope* create(JSContext* cx, Handle<Data*> data,
                                Handle<ModuleObject*> module, HandleScope enclosing);
 
   private:
     static ModuleScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
                                        Handle<ModuleObject*> module, HandleScope enclosing);
 
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
   public:
     uint32_t nextFrameSlot() const {
         return data().nextFrameSlot;
     }
 
     ModuleObject* module() const {
@@ -1037,17 +1028,17 @@ class ModuleScope : public Scope
 
 class WasmInstanceScope : public Scope
 {
     friend class BindingIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
 
   public:
-    struct Data : BaseScopeData
+    struct Data : public BaseScopeData
     {
         uint32_t memoriesStart = 0;
         uint32_t globalsStart = 0;
         uint32_t length = 0;
         uint32_t nextFrameSlot = 0;
 
         // The wasm instance of the scope.
         GCPtr<WasmInstanceObject*> instance = {};
@@ -1059,21 +1050,21 @@ class WasmInstanceScope : public Scope
 
         void trace(JSTracer* trc);
     };
 
     static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
 
   private:
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
   public:
     WasmInstanceObject* instance() const {
         return data().instance;
     }
 
     uint32_t memoriesStart() const {
@@ -1096,17 +1087,17 @@ class WasmInstanceScope : public Scope
 //
 class WasmFunctionScope : public Scope
 {
     friend class BindingIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
 
   public:
-    struct Data : BaseScopeData
+    struct Data : public BaseScopeData
     {
         uint32_t length = 0;
         uint32_t nextFrameSlot = 0;
         uint32_t funcIndex = 0;
 
         TrailingNamesArray trailingNames;
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
@@ -1114,21 +1105,21 @@ class WasmFunctionScope : public Scope
 
         void trace(JSTracer* trc);
     };
 
     static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex);
 
   private:
     Data& data() {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
     const Data& data() const {
-        return *reinterpret_cast<Data*>(data_);
+        return *static_cast<Data*>(data_);
     }
 
   public:
     uint32_t funcIndex() const {
         return data().funcIndex;
     }
 
     static Shape* getEmptyEnvironmentShape(JSContext* cx);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2146,27 +2146,28 @@ intrinsic_HostResolveImportedModule(JSCo
     RootedString specifier(cx, args[1].toString());
 
     JS::ModuleResolveHook moduleResolveHook = cx->runtime()->moduleResolveHook;
     if (!moduleResolveHook) {
         JS_ReportErrorASCII(cx, "Module resolve hook not set");
         return false;
     }
 
-    RootedObject result(cx);
-    result = moduleResolveHook(cx, module, specifier);
+    RootedScript script(cx, module->script());
+    RootedScript result(cx);
+    result = moduleResolveHook(cx, script, specifier);
     if (!result)
         return false;
 
-    if (!result->is<ModuleObject>()) {
-        JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
+    if (!result->module()) {
+        JS_ReportErrorASCII(cx, "Module resolve hook did not return a module script");
         return false;
     }
 
-    args.rval().setObject(*result);
+    args.rval().setObject(*result->module());
     return true;
 }
 
 static bool
 intrinsic_CreateImportBinding(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 4);
--- a/js/src/vm/StringType-inl.h
+++ b/js/src/vm/StringType-inl.h
@@ -92,23 +92,37 @@ JSString::validateLength(JSContext* mayb
     if (MOZ_UNLIKELY(length > JSString::MAX_LENGTH)) {
         js::ReportAllocationOverflow(maybecx);
         return false;
     }
 
     return true;
 }
 
+template<>
+MOZ_ALWAYS_INLINE const char16_t*
+JSString::nonInlineCharsRaw() const
+{
+    return d.s.u2.nonInlineCharsTwoByte;
+}
+
+template<>
+MOZ_ALWAYS_INLINE const JS::Latin1Char*
+JSString::nonInlineCharsRaw() const
+{
+    return d.s.u2.nonInlineCharsLatin1;
+}
+
 MOZ_ALWAYS_INLINE void
 JSRope::init(JSContext* cx, JSString* left, JSString* right, size_t length)
 {
-    d.u1.length = length;
-    d.u1.flags = INIT_ROPE_FLAGS;
     if (left->hasLatin1Chars() && right->hasLatin1Chars())
-        d.u1.flags |= LATIN1_CHARS_BIT;
+        setLengthAndFlags(length, INIT_ROPE_FLAGS | LATIN1_CHARS_BIT);
+    else
+        setLengthAndFlags(length, INIT_ROPE_FLAGS);
     d.s.u2.left = left;
     d.s.u3.right = right;
 
     // Post-barrier by inserting into the whole cell buffer if either
     // this -> left or this -> right is a tenured -> nursery edge.
     if (isTenured()) {
         js::gc::StoreBuffer* sb = left->storeBuffer();
         if (!sb)
@@ -134,23 +148,22 @@ JSRope::new_(JSContext* cx,
     return str;
 }
 
 MOZ_ALWAYS_INLINE void
 JSDependentString::init(JSContext* cx, JSLinearString* base, size_t start,
                         size_t length)
 {
     MOZ_ASSERT(start + length <= base->length());
-    d.u1.length = length;
     JS::AutoCheckCannotGC nogc;
     if (base->hasLatin1Chars()) {
-        d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
+        setLengthAndFlags(length, DEPENDENT_FLAGS | LATIN1_CHARS_BIT);
         d.s.u2.nonInlineCharsLatin1 = base->latin1Chars(nogc) + start;
     } else {
-        d.u1.flags = DEPENDENT_FLAGS;
+        setLengthAndFlags(length, DEPENDENT_FLAGS);
         d.s.u2.nonInlineCharsTwoByte = base->twoByteChars(nogc) + start;
     }
     d.s.u3.base = base;
     if (isTenured() && !base->isTenured())
         base->storeBuffer()->putWholeCell(this);
 }
 
 MOZ_ALWAYS_INLINE JSLinearString*
@@ -201,26 +214,24 @@ JSDependentString::new_(JSContext* cx, J
         return nullptr;
     str->init(cx, base, start, length);
     return str;
 }
 
 MOZ_ALWAYS_INLINE void
 JSFlatString::init(const char16_t* chars, size_t length)
 {
-    d.u1.length = length;
-    d.u1.flags = INIT_FLAT_FLAGS;
+    setLengthAndFlags(length, INIT_FLAT_FLAGS);
     d.s.u2.nonInlineCharsTwoByte = chars;
 }
 
 MOZ_ALWAYS_INLINE void
 JSFlatString::init(const JS::Latin1Char* chars, size_t length)
 {
-    d.u1.length = length;
-    d.u1.flags = INIT_FLAT_FLAGS | LATIN1_CHARS_BIT;
+    setLengthAndFlags(length, INIT_FLAT_FLAGS | LATIN1_CHARS_BIT);
     d.s.u2.nonInlineCharsLatin1 = chars;
 }
 
 template <js::AllowGC allowGC, typename CharT>
 MOZ_ALWAYS_INLINE JSFlatString*
 JSFlatString::new_(JSContext* cx, const CharT* chars, size_t length)
 {
     MOZ_ASSERT(chars[length] == CharT(0));
@@ -289,58 +300,53 @@ JSFatInlineString::new_(JSContext* cx)
     return js::Allocate<JSFatInlineString, allowGC>(cx, js::gc::DefaultHeap);
 }
 
 template<>
 MOZ_ALWAYS_INLINE JS::Latin1Char*
 JSThinInlineString::init<JS::Latin1Char>(size_t length)
 {
     MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
-    d.u1.length = length;
-    d.u1.flags = INIT_THIN_INLINE_FLAGS | LATIN1_CHARS_BIT;
+    setLengthAndFlags(length, INIT_THIN_INLINE_FLAGS | LATIN1_CHARS_BIT);
     return d.inlineStorageLatin1;
 }
 
 template<>
 MOZ_ALWAYS_INLINE char16_t*
 JSThinInlineString::init<char16_t>(size_t length)
 {
     MOZ_ASSERT(lengthFits<char16_t>(length));
-    d.u1.length = length;
-    d.u1.flags = INIT_THIN_INLINE_FLAGS;
+    setLengthAndFlags(length, INIT_THIN_INLINE_FLAGS);
     return d.inlineStorageTwoByte;
 }
 
 template<>
 MOZ_ALWAYS_INLINE JS::Latin1Char*
 JSFatInlineString::init<JS::Latin1Char>(size_t length)
 {
     MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
-    d.u1.length = length;
-    d.u1.flags = INIT_FAT_INLINE_FLAGS | LATIN1_CHARS_BIT;
+    setLengthAndFlags(length, INIT_FAT_INLINE_FLAGS | LATIN1_CHARS_BIT);
     return d.inlineStorageLatin1;
 }
 
 template<>
 MOZ_ALWAYS_INLINE char16_t*
 JSFatInlineString::init<char16_t>(size_t length)
 {
     MOZ_ASSERT(lengthFits<char16_t>(length));
-    d.u1.length = length;
-    d.u1.flags = INIT_FAT_INLINE_FLAGS;
+    setLengthAndFlags(length, INIT_FAT_INLINE_FLAGS);
     return d.inlineStorageTwoByte;
 }
 
 MOZ_ALWAYS_INLINE void
 JSExternalString::init(const char16_t* chars, size_t length, const JSStringFinalizer* fin)
 {
     MOZ_ASSERT(fin);
     MOZ_ASSERT(fin->finalize);
-    d.u1.length = length;
-    d.u1.flags = EXTERNAL_FLAGS;
+    setLengthAndFlags(length, EXTERNAL_FLAGS);
     d.s.u2.nonInlineCharsTwoByte = chars;
     d.s.u3.externalFinalizer = fin;
 }
 
 MOZ_ALWAYS_INLINE JSExternalString*
 JSExternalString::new_(JSContext* cx, const char16_t* chars, size_t length,
                        const JSStringFinalizer* fin)
 {
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -207,17 +207,17 @@ JSString::dumpRepresentation(js::Generic
     else if (isFlat())          asFlat()        .dumpRepresentation(out, indent);
     else
         MOZ_CRASH("Unexpected JSString representation");
 }
 
 void
 JSString::dumpRepresentationHeader(js::GenericPrinter& out, const char* subclass) const
 {
-    uint32_t flags = d.u1.flags;
+    uint32_t flags = JSString::flags();
     // Print the string's address as an actual C++ expression, to facilitate
     // copy-and-paste into a debugger.
     out.printf("((%s*) %p) length: %zu  flags: 0x%x", subclass, this, length(), flags);
     if (flags & LINEAR_BIT)             out.put(" LINEAR");
     if (flags & HAS_BASE_BIT)           out.put(" HAS_BASE");
     if (flags & INLINE_CHARS_BIT)       out.put(" INLINE_CHARS");
     if (flags & NON_ATOM_BIT)           out.put(" NON_ATOM");
     else                                out.put(" (ATOM)");
@@ -513,20 +513,18 @@ JSRope::flattenInternal(JSContext* maybe
      * pointers in the JSDependentStrings are still valid.
      */
     const size_t wholeLength = length();
     size_t wholeCapacity;
     CharT* wholeChars;
     JSString* str = this;
     CharT* pos;
 
-    /*
-     * JSString::flattenData is a tagged pointer to the parent node.
-     * The tag indicates what to do when we return to the parent.
-     */
+    // JSString::setFlattenData() is used to store a tagged pointer to the
+    // parent node. The tag indicates what to do when we return to the parent.
     static const uintptr_t Tag_Mask = 0x3;
     static const uintptr_t Tag_FinishNode = 0x0;
     static const uintptr_t Tag_VisitRightChild = 0x1;
 
     AutoCheckCannotGC nogc;
 
     gc::StoreBuffer* bufferIfNursery = storeBuffer();
 
@@ -551,29 +549,30 @@ JSRope::flattenInternal(JSContext* maybe
                 if (b == WithIncrementalBarrier) {
                     JSString::writeBarrierPre(str->d.s.u2.left);
                     JSString::writeBarrierPre(str->d.s.u3.right);
                 }
                 JSString* child = str->d.s.u2.left;
                 // 'child' will be post-barriered during the later traversal.
                 MOZ_ASSERT(child->isRope());
                 str->setNonInlineChars(wholeChars);
-                child->d.u1.flattenData = uintptr_t(str) | Tag_VisitRightChild;
+                child->setFlattenData(uintptr_t(str) | Tag_VisitRightChild);
                 str = child;
             }
             if (b == WithIncrementalBarrier) {
                 JSString::writeBarrierPre(str->d.s.u2.left);
                 JSString::writeBarrierPre(str->d.s.u3.right);
             }
             str->setNonInlineChars(wholeChars);
-            pos = wholeChars + left.d.u1.length;
+            uint32_t left_len = left.length();
+            pos = wholeChars + left_len;
             if (IsSame<CharT, char16_t>::value)
-                left.d.u1.flags = DEPENDENT_FLAGS;
+                left.setLengthAndFlags(left_len, DEPENDENT_FLAGS);
             else
-                left.d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
+                left.setLengthAndFlags(left_len, DEPENDENT_FLAGS | LATIN1_CHARS_BIT);
             left.d.s.u3.base = (JSLinearString*)this;  /* will be true on exit */
             Nursery& nursery = runtimeFromMainThread()->gc.nursery();
             bool inTenured = !bufferIfNursery;
             if (!inTenured && left.isTenured()) {
                 // tenured leftmost child is giving its chars buffer to the
                 // nursery-allocated root node.
                 nursery.registerMallocedBuffer(wholeChars);
                 // leftmost child -> root is a tenured -> nursery edge.
@@ -609,54 +608,53 @@ JSRope::flattenInternal(JSContext* maybe
             JSString::writeBarrierPre(str->d.s.u2.left);
             JSString::writeBarrierPre(str->d.s.u3.right);
         }
 
         JSString& left = *str->d.s.u2.left;
         str->setNonInlineChars(pos);
         if (left.isRope()) {
             /* Return to this node when 'left' done, then goto visit_right_child. */
-            left.d.u1.flattenData = uintptr_t(str) | Tag_VisitRightChild;
+            left.setFlattenData(uintptr_t(str) | Tag_VisitRightChild);
             str = &left;
             goto first_visit_node;
         }
         CopyChars(pos, left.asLinear());
         pos += left.length();
     }
     visit_right_child: {
         JSString& right = *str->d.s.u3.right;
         if (right.isRope()) {
             /* Return to this node when 'right' done, then goto finish_node. */
-            right.d.u1.flattenData = uintptr_t(str) | Tag_FinishNode;
+            right.setFlattenData(uintptr_t(str) | Tag_FinishNode);
             str = &right;
             goto first_visit_node;
         }
         CopyChars(pos, right.asLinear());
         pos += right.length();
     }
 
     finish_node: {
         if (str == this) {
             MOZ_ASSERT(pos == wholeChars + wholeLength);
             *pos = '\0';
-            str->d.u1.length = wholeLength;
             if (IsSame<CharT, char16_t>::value)
-                str->d.u1.flags = EXTENSIBLE_FLAGS;
+                str->setLengthAndFlags(wholeLength, EXTENSIBLE_FLAGS);
             else
-                str->d.u1.flags = EXTENSIBLE_FLAGS | LATIN1_CHARS_BIT;
+                str->setLengthAndFlags(wholeLength, EXTENSIBLE_FLAGS | LATIN1_CHARS_BIT);
             str->setNonInlineChars(wholeChars);
             str->d.s.u3.capacity = wholeCapacity;
             return &this->asFlat();
         }
-        uintptr_t flattenData = str->d.u1.flattenData;
+        uintptr_t flattenData;
+        uint32_t len = pos - str->nonInlineCharsRaw<CharT>();
         if (IsSame<CharT, char16_t>::value)
-            str->d.u1.flags = DEPENDENT_FLAGS;
+            flattenData = str->unsetFlattenData(len, DEPENDENT_FLAGS);
         else
-            str->d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
-        str->d.u1.length = pos - str->asLinear().nonInlineChars<CharT>(nogc);
+            flattenData = str->unsetFlattenData(len, DEPENDENT_FLAGS | LATIN1_CHARS_BIT);
         str->d.s.u3.base = (JSLinearString*)this;       /* will be true on exit */
 
         // Every interior (rope) node in the rope's tree will be visited during
         // the traversal and post-barriered here, so earlier additions of
         // dependent.base -> root pointers are handled by this barrier as well.
         //
         // The only time post-barriers need do anything is when the root is in
         // the nursery. Note that the root was a rope but will be an extensible
@@ -801,19 +799,19 @@ JSDependentString::undependInternal(JSCo
     s[n] = '\0';
     setNonInlineChars<CharT>(s.release());
 
     /*
      * Transform *this into an undepended string so 'base' will remain rooted
      * for the benefit of any other dependent string that depends on *this.
      */
     if (IsSame<CharT, Latin1Char>::value)
-        d.u1.flags = UNDEPENDED_FLAGS | LATIN1_CHARS_BIT;
+        setLengthAndFlags(n, UNDEPENDED_FLAGS | LATIN1_CHARS_BIT);
     else
-        d.u1.flags = UNDEPENDED_FLAGS;
+        setLengthAndFlags(n, UNDEPENDED_FLAGS);
 
     return &this->asFlat();
 }
 
 JSFlatString*
 JSDependentString::undepend(JSContext* cx)
 {
     MOZ_ASSERT(JSString::isDependent());
@@ -1378,18 +1376,18 @@ JSExternalString::ensureFlat(JSContext* 
     }
 
     // Release the external chars.
     finalize(cx->runtime()->defaultFreeOp());
 
     // Transform the string into a non-external, flat string. Note that the
     // resulting string will still be in an AllocKind::EXTERNAL_STRING arena,
     // but will no longer be an external string.
+    setLengthAndFlags(n, INIT_FLAT_FLAGS);
     setNonInlineChars<char16_t>(s.release());
-    d.u1.flags = INIT_FLAT_FLAGS;
 
     return &this->asFlat();
 }
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
 void
 JSAtom::dump(js::GenericPrinter& out)
 {
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -160,23 +160,31 @@ class JSString : public js::gc::Cell
 {
   protected:
     static const size_t NUM_INLINE_CHARS_LATIN1   = 2 * sizeof(void*) / sizeof(JS::Latin1Char);
     static const size_t NUM_INLINE_CHARS_TWO_BYTE = 2 * sizeof(void*) / sizeof(char16_t);
 
     /* Fields only apply to string types commented on the right. */
     struct Data
     {
-        union {
-            struct {
-                uint32_t           flags;               /* JSString */
-                uint32_t           length;              /* JSString */
-            };
-            uintptr_t              flattenData;         /* JSRope (temporary while flattening) */
-        } u1;
+        // First word of a Cell has additional requirements from GC and normally
+        // would store a pointer. If a single word isn't large enough, the length
+        // is stored separately.
+        //          32      16       0
+        //  --------------------------
+        //  | Length | Index | Flags |
+        //  --------------------------
+        //
+        // NOTE: This is also used for temporary storage while linearizing a Rope.
+        uintptr_t flags_;                               /* JSString */
+
+#if JS_BITS_PER_WORD == 32
+        // Additional storage for length if |flags_| is too small to fit both.
+        uint32_t                   length_;             /* JSString */
+#endif
         union {
             union {
                 /* JS(Fat)InlineString */
                 JS::Latin1Char     inlineStorageLatin1[NUM_INLINE_CHARS_LATIN1];
                 char16_t           inlineStorageTwoByte[NUM_INLINE_CHARS_TWO_BYTE];
             };
             struct {
                 union {
@@ -193,19 +201,21 @@ class JSString : public js::gc::Cell
             } s;
         };
     } d;
 
   public:
     /* Flags exposed only for jits */
 
     /*
-     * The Flags Word
+     * Flag Encoding
      *
-     * The flags word stores both the string's type and its character encoding.
+     * The first word of a JSString stores flags, index, and (on some
+     * platforms) the length. The flags store both the string's type and its
+     * character encoding.
      *
      * If LATIN1_CHARS_BIT is set, the string's characters are stored as Latin1
      * instead of TwoByte. This flag can also be set for ropes, if both the
      * left and right nodes are Latin1. Flattening will result in a Latin1
      * string in this case.
      *
      * The other flags store the string's type. Instead of using a dense index
      * to represent the most-derived type, string types are encoded to allow
@@ -247,56 +257,55 @@ class JSString : public js::gc::Cell
      *   Bit 3: IsInline (Inline, FatInline)
      *
      *  "HasBase" here refers to the two string types that have a 'base' field:
      *  JSDependentString and JSUndependedString.
      *  A JSUndependedString is a JSDependentString which has been 'fixed' (by ensureFixed)
      *  to be null-terminated.  In such cases, the string must keep marking its base since
      *  there may be any number of *other* JSDependentStrings transitively depending on it.
      *
-     * The atom bit (NON_ATOM_BIT) is inverted so that objects and strings can
-     * be differentiated in the nursery: atoms are never in the nursery, so
-     * this bit is always 1 for a nursery string. For an object on a
-     * little-endian architecture, this is the low-order bit of the ObjectGroup
-     * pointer in a JSObject, which will always be zero. A 64-bit big-endian
-     * architecture will need to do something else (the ObjectGroup* is in the
-     * same place as a string's struct { uint32_t flags; uint32_t length; }).
+     * The atom bit (NON_ATOM_BIT) is inverted and stored in a Cell
+     * ReservedBit. Atoms are never stored in nursery, so the nursery can use
+     * this bit to distinguish between JSString (1) and JSObject (0).
      *
-     * If the INDEX_VALUE_BIT is set the upper 16 bits of the flag word hold the integer
-     * index.
+     * If the INDEX_VALUE_BIT is set, flags will also hold an integer index.
      */
 
-    static const uint32_t NON_ATOM_BIT           = JS_BIT(0);
-    static const uint32_t LINEAR_BIT             = JS_BIT(1);
-    static const uint32_t HAS_BASE_BIT           = JS_BIT(2);
-    static const uint32_t INLINE_CHARS_BIT       = JS_BIT(3);
+    // The low bits of flag word are reserved by GC.
+    static_assert(js::gc::Cell::ReservedBits <= 3,
+                  "JSString::flags must reserve enough bits for Cell");
+
+    static const uint32_t NON_ATOM_BIT           = js::gc::Cell::JSSTRING_BIT;
+    static const uint32_t LINEAR_BIT             = JS_BIT(4);
+    static const uint32_t HAS_BASE_BIT           = JS_BIT(5);
+    static const uint32_t INLINE_CHARS_BIT       = JS_BIT(6);
 
     static const uint32_t DEPENDENT_FLAGS        = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT;
-    static const uint32_t UNDEPENDED_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT | JS_BIT(4);
-    static const uint32_t EXTENSIBLE_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(4);
-    static const uint32_t EXTERNAL_FLAGS         = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(5);
+    static const uint32_t UNDEPENDED_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT | JS_BIT(7);
+    static const uint32_t EXTENSIBLE_FLAGS       = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(7);
+    static const uint32_t EXTERNAL_FLAGS         = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(8);
 
-    static const uint32_t FAT_INLINE_MASK        = INLINE_CHARS_BIT | JS_BIT(4);
-    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(5);
-    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(5);
+    static const uint32_t FAT_INLINE_MASK        = INLINE_CHARS_BIT | JS_BIT(7);
+    static const uint32_t PERMANENT_ATOM_MASK    = NON_ATOM_BIT | JS_BIT(8);
+    static const uint32_t PERMANENT_ATOM_FLAGS   = JS_BIT(8);
 
     /* Initial flags for thin inline and fat inline strings. */
     static const uint32_t INIT_THIN_INLINE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | INLINE_CHARS_BIT;
     static const uint32_t INIT_FAT_INLINE_FLAGS  = NON_ATOM_BIT | LINEAR_BIT | FAT_INLINE_MASK;
     static const uint32_t INIT_ROPE_FLAGS        = NON_ATOM_BIT;
     static const uint32_t INIT_FLAT_FLAGS        = NON_ATOM_BIT | LINEAR_BIT;
 
-    static const uint32_t TYPE_FLAGS_MASK        = JS_BIT(6) - 1;
+    static const uint32_t TYPE_FLAGS_MASK        = JS_BITMASK(9) - JS_BITMASK(3) + js::gc::Cell::JSSTRING_BIT;
 
-    static const uint32_t LATIN1_CHARS_BIT       = JS_BIT(6);
+    static const uint32_t LATIN1_CHARS_BIT       = JS_BIT(9);
 
-    static const uint32_t INDEX_VALUE_BIT        = JS_BIT(7);
+    static const uint32_t INDEX_VALUE_BIT        = JS_BIT(10);
     static const uint32_t INDEX_VALUE_SHIFT      = 16;
 
-    static const uint32_t PINNED_ATOM_BIT        = JS_BIT(8);
+    static const uint32_t PINNED_ATOM_BIT        = JS_BIT(11);
 
     static const uint32_t MAX_LENGTH             = js::MaxStringLength;
 
     static const JS::Latin1Char MAX_LATIN1_CHAR = 0xff;
 
     /*
      * Helper function to validate that a string of a given length is
      * representable by a JSString. An allocation overflow is reported if false
@@ -312,20 +321,22 @@ class JSString : public js::gc::Cell
                       "Inline Latin1 chars must fit in a JSString");
         static_assert(sizeof(JSString) ==
                       (offsetof(JSString, d.inlineStorageTwoByte) +
                        NUM_INLINE_CHARS_TWO_BYTE * sizeof(char16_t)),
                       "Inline char16_t chars must fit in a JSString");
 
         /* Ensure js::shadow::String has the same layout. */
         using JS::shadow::String;
-        static_assert(offsetof(JSString, d.u1.length) == offsetof(String, length),
+        static_assert(offsetof(JSString, d.flags_) == offsetof(String, flags_),
+                      "shadow::String flags offset must match JSString");
+#if JS_BITS_PER_WORD == 32
+        static_assert(offsetof(JSString, d.length_) == offsetof(String, length_),
                       "shadow::String length offset must match JSString");
-        static_assert(offsetof(JSString, d.u1.flags) == offsetof(String, flags),
-                      "shadow::String flags offset must match JSString");
+#endif
         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(String, nonInlineCharsLatin1),
                       "shadow::String nonInlineChars offset must match JSString");
         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(String, nonInlineCharsTwoByte),
                       "shadow::String nonInlineChars offset must match JSString");
         static_assert(offsetof(JSString, d.s.u3.externalFinalizer) == offsetof(String, externalFinalizer),
                       "shadow::String externalFinalizer offset must match JSString");
         static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(String, inlineStorageLatin1),
                       "shadow::String inlineStorage offset must match JSString");
@@ -350,85 +361,135 @@ class JSString : public js::gc::Cell
 
     friend class js::gc::RelocationOverlay;
 
   protected:
     template <typename CharT>
     MOZ_ALWAYS_INLINE
     void setNonInlineChars(const CharT* chars);
 
+    MOZ_ALWAYS_INLINE
+    uint32_t flags() const {
+        return uint32_t(d.flags_);
+    }
+
   public:
-    /* All strings have length. */
+    MOZ_ALWAYS_INLINE
+    size_t length() const {
+#if JS_BITS_PER_WORD == 32
+        return d.length_;
+#else
+        return uint32_t(d.flags_ >> 32);
+#endif
+    }
+
+  protected:
+    MOZ_ALWAYS_INLINE
+    void setFlagBit(uint32_t flags) {
+        d.flags_ |= uintptr_t(flags);
+    }
 
     MOZ_ALWAYS_INLINE
-    size_t length() const {
-        return d.u1.length;
+    void clearFlagBit(uint32_t flags) {
+        d.flags_ &= ~uintptr_t(flags);
     }
 
     MOZ_ALWAYS_INLINE
+    void setLengthAndFlags(uint32_t len, uint32_t flags) {
+#if JS_BITS_PER_WORD == 32
+        d.flags_ = flags;
+        d.length_ = len;
+#else
+        d.flags_ = uint64_t(len) << 32 | uint64_t(flags);
+#endif
+    }
+
+    // Flatten algorithm stores a temporary word by clobbering flags. This is
+    // not GC-safe and user must ensure JSString::flags are never checked
+    // (including by asserts) while this data is stored.
+    MOZ_ALWAYS_INLINE
+    void setFlattenData(uintptr_t data) {
+        d.flags_ = data;
+    }
+
+    // To get back the data, values to safely re-initialize clobbered flags
+    // must be provided.
+    MOZ_ALWAYS_INLINE
+    uintptr_t unsetFlattenData(uint32_t len, uint32_t flags) {
+        uintptr_t data = d.flags_;
+        setLengthAndFlags(len, flags);
+        return data;
+    }
+
+    // Get correct non-inline chars enum arm for given type
+    template <typename CharT> MOZ_ALWAYS_INLINE const CharT* nonInlineCharsRaw() const;
+
+  public:
+
+    MOZ_ALWAYS_INLINE
     bool empty() const {
-        return d.u1.length == 0;
+        return length() == 0;
     }
 
     inline bool getChar(JSContext* cx, size_t index, char16_t* code);
 
     /* Strings have either Latin1 or TwoByte chars. */
     bool hasLatin1Chars() const {
-        return d.u1.flags & LATIN1_CHARS_BIT;
+        return flags() & LATIN1_CHARS_BIT;
     }
     bool hasTwoByteChars() const {
-        return !(d.u1.flags & LATIN1_CHARS_BIT);
+        return !(flags() & LATIN1_CHARS_BIT);
     }
 
     /* Strings might contain cached indexes. */
     bool hasIndexValue() const {
-        return d.u1.flags & INDEX_VALUE_BIT;
+        return flags() & INDEX_VALUE_BIT;
     }
     uint32_t getIndexValue() const {
         MOZ_ASSERT(hasIndexValue());
         MOZ_ASSERT(isFlat());
-        return d.u1.flags >> INDEX_VALUE_SHIFT;
+        return flags() >> INDEX_VALUE_SHIFT;
     }
 
     /* Fallible conversions to more-derived string types. */
 
     inline JSLinearString* ensureLinear(JSContext* cx);
     JSFlatString* ensureFlat(JSContext* cx);
 
     static bool ensureLinear(JSContext* cx, JSString* str) {
         return str->ensureLinear(cx) != nullptr;
     }
 
     /* Type query and debug-checked casts */
 
     MOZ_ALWAYS_INLINE
     bool isRope() const {
-        return !(d.u1.flags & LINEAR_BIT);
+        return !(flags() & LINEAR_BIT);
     }
 
     MOZ_ALWAYS_INLINE
     JSRope& asRope() const {
         MOZ_ASSERT(isRope());
         return *(JSRope*)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isLinear() const {
-        return d.u1.flags & LINEAR_BIT;
+        return flags() & LINEAR_BIT;
     }
 
     MOZ_ALWAYS_INLINE
     JSLinearString& asLinear() const {
         MOZ_ASSERT(JSString::isLinear());
         return *(JSLinearString*)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isDependent() const {
-        return (d.u1.flags & TYPE_FLAGS_MASK) == DEPENDENT_FLAGS;
+        return (flags() & TYPE_FLAGS_MASK) == DEPENDENT_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSDependentString& asDependent() const {
         MOZ_ASSERT(isDependent());
         return *(JSDependentString*)this;
     }
 
@@ -440,111 +501,119 @@ class JSString : public js::gc::Cell
     MOZ_ALWAYS_INLINE
     JSFlatString& asFlat() const {
         MOZ_ASSERT(isFlat());
         return *(JSFlatString*)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isExtensible() const {
-        return (d.u1.flags & TYPE_FLAGS_MASK) == EXTENSIBLE_FLAGS;
+        return (flags() & TYPE_FLAGS_MASK) == EXTENSIBLE_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSExtensibleString& asExtensible() const {
         MOZ_ASSERT(isExtensible());
         return *(JSExtensibleString*)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isInline() const {
-        return d.u1.flags & INLINE_CHARS_BIT;
+        return flags() & INLINE_CHARS_BIT;
     }
 
     MOZ_ALWAYS_INLINE
     JSInlineString& asInline() const {
         MOZ_ASSERT(isInline());
         return *(JSInlineString*)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isFatInline() const {
-        return (d.u1.flags & FAT_INLINE_MASK) == FAT_INLINE_MASK;
+        return (flags() & FAT_INLINE_MASK) == FAT_INLINE_MASK;
     }
 
     /* For hot code, prefer other type queries. */
     bool isExternal() const {
-        return (d.u1.flags & TYPE_FLAGS_MASK) == EXTERNAL_FLAGS;
+        return (flags() & TYPE_FLAGS_MASK) == EXTERNAL_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSExternalString& asExternal() const {
         MOZ_ASSERT(isExternal());
         return *(JSExternalString*)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isUndepended() const {
-        return (d.u1.flags & TYPE_FLAGS_MASK) == UNDEPENDED_FLAGS;
+        return (flags() & TYPE_FLAGS_MASK) == UNDEPENDED_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     bool isAtom() const {
-        return !(d.u1.flags & NON_ATOM_BIT);
+        return !(flags() & NON_ATOM_BIT);
     }
 
     MOZ_ALWAYS_INLINE
     bool isPermanentAtom() const {
-        return (d.u1.flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
+        return (flags() & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSAtom& asAtom() const {
         MOZ_ASSERT(isAtom());
         return *(JSAtom*)this;
     }
 
-    // Used for distinguishing strings from objects in the nursery. The caller
-    // must ensure that cell is in the nursery (and not forwarded).
-    MOZ_ALWAYS_INLINE
-    static bool nurseryCellIsString(js::gc::Cell* cell) {
-        MOZ_ASSERT(!cell->isTenured());
-        return !static_cast<JSString*>(cell)->isAtom();
-    }
-
     // Fills |array| with various strings that represent the different string
     // kinds and character encodings.
     static bool fillWithRepresentatives(JSContext* cx, js::HandleArrayObject array);
 
     /* Only called by the GC for dependent or undepended strings. */
 
     inline bool hasBase() const {
-        return d.u1.flags & HAS_BASE_BIT;
+        return flags() & HAS_BASE_BIT;
     }
 
     inline JSLinearString* base() const;
 
     void traceBase(JSTracer* trc);
 
     /* Only called by the GC for strings with the AllocKind::STRING kind. */
 
     inline void finalize(js::FreeOp* fop);
 
     /* Gets the number of bytes that the chars take on the heap. */
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
-    /* Offsets for direct field from jit code. */
-
-    static size_t offsetOfLength() {
-        return offsetof(JSString, d.u1.length);
+    // Offsets for direct field from jit code. A number of places directly
+    // access 32-bit length and flags fields so do endian trickery here.
+#if JS_BITS_PER_WORD == 32
+    static constexpr size_t offsetOfFlags() {
+        return offsetof(JSString, d.flags_);
+    }
+    static constexpr size_t offsetOfLength() {
+        return offsetof(JSString, d.length_);
     }
-    static size_t offsetOfFlags() {
-        return offsetof(JSString, d.u1.flags);
+#elif defined(MOZ_LITTLE_ENDIAN)
+    static constexpr size_t offsetOfFlags() {
+        return offsetof(JSString, d.flags_);
+    }
+    static constexpr size_t offsetOfLength() {
+        return offsetof(JSString, d.flags_) + sizeof(uint32_t);
     }
+#else
+    static constexpr size_t offsetOfFlags() {
+        return offsetof(JSString, d.flags_) + sizeof(uint32_t);
+    }
+    static constexpr size_t offsetOfLength() {
+        return offsetof(JSString, d.flags_);
+    }
+#endif
 
   private:
     // To help avoid writing Spectre-unsafe code, we only allow MacroAssembler
     // to call the method below.
     friend class js::jit::MacroAssembler;
     static size_t offsetOfNonInlineChars() {
         static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) ==
                       offsetof(JSString, d.s.u2.nonInlineCharsLatin1),
@@ -926,17 +995,17 @@ class JSFlatString : public JSLinearStri
 
         if (hasIndexValue() || index > UINT16_MAX)
             return;
 
         mozilla::DebugOnly<uint32_t> containedIndex;
         MOZ_ASSERT(isIndexSlow(&containedIndex));
         MOZ_ASSERT(index == containedIndex);
 
-        d.u1.flags |= (index << INDEX_VALUE_SHIFT) | INDEX_VALUE_BIT;
+        setFlagBit((index << INDEX_VALUE_SHIFT) | INDEX_VALUE_BIT);
     }
 
     /*
      * Returns a property name represented by this string, or null on failure.
      * You must verify that this is not an index per isIndex before calling
      * this method.
      */
     inline js::PropertyName* toPropertyName(JSContext* cx);
@@ -1162,29 +1231,29 @@ class JSAtom : public JSFlatString
     bool isPermanent() const {
         return JSString::isPermanentAtom();
     }
 
     // Transform this atom into a permanent atom. This is only done during
     // initialization of the runtime. Permanent atoms are always pinned.
     MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
         MOZ_ASSERT(static_cast<JSString*>(this)->isAtom());
-        d.u1.flags |= PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT;
+        setFlagBit(PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT);
     }
 
     MOZ_ALWAYS_INLINE
     bool isPinned() const {
-        return d.u1.flags & PINNED_ATOM_BIT;
+        return flags() & PINNED_ATOM_BIT;
     }
 
     // Mark the atom as pinned. For use by atomization only.
     MOZ_ALWAYS_INLINE void setPinned() {
         MOZ_ASSERT(static_cast<JSString*>(this)->isAtom());
         MOZ_ASSERT(!isPinned());
-        d.u1.flags |= PINNED_ATOM_BIT;
+        setFlagBit(PINNED_ATOM_BIT);
     }
 
     inline js::HashNumber hash() const;
     inline void initHash(js::HashNumber hash);
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
     void dump(js::GenericPrinter& out);
     void dump();
@@ -1252,28 +1321,28 @@ JSAtom::initHash(js::HashNumber hash)
         return static_cast<js::FatInlineAtom*>(this)->initHash(hash);
     return static_cast<js::NormalAtom*>(this)->initHash(hash);
 }
 
 MOZ_ALWAYS_INLINE JSAtom*
 JSFlatString::morphAtomizedStringIntoAtom(js::HashNumber hash)
 {
     MOZ_ASSERT(!isAtom());
-    d.u1.flags &= ~NON_ATOM_BIT;
+    clearFlagBit(NON_ATOM_BIT);
     JSAtom* atom = &asAtom();
     atom->initHash(hash);
     return atom;
 }
 
 MOZ_ALWAYS_INLINE JSAtom*
 JSFlatString::morphAtomizedStringIntoPermanentAtom(js::HashNumber hash)
 {
     MOZ_ASSERT(!isAtom());
-    d.u1.flags |= PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT;
-    d.u1.flags &= ~NON_ATOM_BIT;
+    setFlagBit(PERMANENT_ATOM_FLAGS | PINNED_ATOM_BIT);
+    clearFlagBit(NON_ATOM_BIT);
     JSAtom* atom = &asAtom();
     atom->initHash(hash);
     return atom;
 }
 
 namespace js {
 
 class StaticStrings
--- a/js/src/vm/SymbolType.h
+++ b/js/src/vm/SymbolType.h
@@ -27,45 +27,48 @@
 namespace js {
 class AutoAccessAtomsZone;
 } // namespace js
 
 namespace JS {
 
 class Symbol : public js::gc::TenuredCell
 {
+  protected:
+    // Reserved word for Cell GC invariants. This also ensures minimum
+    // structure size.
+    uintptr_t reserved_;
+
   private:
     SymbolCode code_;
 
     // Each Symbol gets its own hash code so that we don't have to use
     // addresses as hash codes (a security hazard).
     js::HashNumber hash_;
 
     JSAtom* description_;
 
-    // The minimum allocation size is sizeof(JSString): 16 bytes on 32-bit
-    // architectures and 24 bytes on 64-bit.  A size_t of padding makes Symbol
-    // the minimum size on both.
-    size_t unused_;
-
     Symbol(SymbolCode code, js::HashNumber hash, JSAtom* desc)
-        : code_(code), hash_(hash), description_(desc)
-    {
-        // Silence warnings about unused_ being... unused.
-        (void)unused_;
-        static_assert(uint32_t(SymbolCode::WellKnownAPILimit) == JS::shadow::Symbol::WellKnownAPILimit,
-                      "JS::shadow::Symbol::WellKnownAPILimit must match SymbolCode::WellKnownAPILimit");
-    }
+        : reserved_(0), code_(code), hash_(hash), description_(desc) { }
 
     Symbol(const Symbol&) = delete;
     void operator=(const Symbol&) = delete;
 
     static Symbol*
     newInternal(JSContext* cx, SymbolCode code, js::HashNumber hash, JSAtom* description);
 
+    static void staticAsserts() {
+        static_assert(uint32_t(SymbolCode::WellKnownAPILimit) == JS::shadow::Symbol::WellKnownAPILimit,
+                      "JS::shadow::Symbol::WellKnownAPILimit must match SymbolCode::WellKnownAPILimit");
+        static_assert(offsetof(Symbol, reserved_) == offsetof(JS::shadow::Symbol, reserved_),
+                      "JS::shadow::Symbol::reserved_ offset must match SymbolCode::reserved_");
+        static_assert(offsetof(Symbol, code_) == offsetof(JS::shadow::Symbol, code_),
+                      "JS::shadow::Symbol::code_ offset must match SymbolCode::code_");
+    }
+
   public:
     static Symbol* new_(JSContext* cx, SymbolCode code, JSString* description);
     static Symbol* for_(JSContext* cx, js::HandleString description);
 
     JSAtom* description() const { return description_; }
     SymbolCode code() const { return code_; }
     js::HashNumber hash() const { return hash_; }
 
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -6486,18 +6486,17 @@ struct ScopedCacheEntryOpenedForRead
 
 static JS::AsmJSCacheResult
 StoreAsmJSModuleInCache(AsmJSParser& parser, Module& module, JSContext* cx)
 {
     ModuleCharsForStore moduleChars;
     if (!moduleChars.init(parser))
         return JS::AsmJSCache_InternalError;
 
-    size_t bytecodeSize = module.bytecodeSerializedSize();
-    MOZ_RELEASE_ASSERT(bytecodeSize == 0);
+    MOZ_RELEASE_ASSERT(module.bytecode().length() == 0);
 
     size_t compiledSize = module.compiledSerializedSize();
     MOZ_RELEASE_ASSERT(compiledSize <= UINT32_MAX);
 
     size_t serializedSize = sizeof(uint32_t) +
                             compiledSize +
                             moduleChars.serializedSize();
 
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -445,42 +445,46 @@ wasm::CompileBuffer(const CompileArgs& a
         return nullptr;
 
     if (!DecodeModuleTail(d, &env))
         return nullptr;
 
     return mg.finishModule(bytecode);
 }
 
-bool
+void
 wasm::CompileTier2(const CompileArgs& args, Module& module, Atomic<bool>* cancelled)
 {
     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
 
     UniqueChars error;
     Decoder d(module.bytecode().bytes, 0, &error);
 
     MOZ_ASSERT(args.gcTypesEnabled == HasGcTypes::False, "can't ion-compile with gc types yet");
 
     ModuleEnvironment env(CompileMode::Tier2, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
                           args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
     if (!DecodeModuleEnvironment(d, &env))
-        return false;
+        return;
 
     ModuleGenerator mg(args, &env, cancelled, &error);
     if (!mg.init())
-        return false;
+        return;
 
     if (!DecodeCodeSection(env, d, mg))
-        return false;
+        return;
 
     if (!DecodeModuleTail(d, &env))
-        return false;
+        return;
 
-    return mg.finishTier2(module);
+    if (!mg.finishTier2(module))
+        return;
+
+    // The caller doesn't care about success or failure; only that compilation
+    // is inactive, so there is no success to return here.
 }
 
 class StreamingDecoder
 {
     Decoder d_;
     const ExclusiveStreamEnd& streamEnd_;
     const Atomic<bool>& cancelled_;
 
--- a/js/src/wasm/WasmCompile.h
+++ b/js/src/wasm/WasmCompile.h
@@ -82,20 +82,19 @@ EstimateCompiledCodeSize(Tier tier, size
 //  - *error is null and the caller should report out-of-memory.
 
 SharedModule
 CompileBuffer(const CompileArgs& args,
               const ShareableBytes& bytecode,
               UniqueChars* error,
               UniqueCharsVector* warnings);
 
-// Attempt to compile the second tier of the given wasm::Module, returning whether
-// tier-2 compilation succeeded and Module::finishTier2 was called.
+// Attempt to compile the second tier of the given wasm::Module.
 
-bool
+void
 CompileTier2(const CompileArgs& args, Module& module, Atomic<bool>* cancelled);
 
 // Compile the given WebAssembly module which has been broken into three
 // partitions:
 //  - envBytes contains a complete ModuleEnvironment that has already been
 //    copied in from the stream.
 //  - codeBytes is pre-sized to hold the complete code section when the stream
 //    completes.
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -170,83 +170,53 @@ LinkData::sizeOfExcludingThis(MallocSize
     return sum;
 }
 
 class Module::Tier2GeneratorTaskImpl : public Tier2GeneratorTask
 {
     SharedModule            module_;
     SharedCompileArgs       compileArgs_;
     Atomic<bool>            cancelled_;
-    bool                    finished_;
 
   public:
     Tier2GeneratorTaskImpl(Module& module, const CompileArgs& compileArgs)
       : module_(&module),
         compileArgs_(&compileArgs),
-        cancelled_(false),
-        finished_(false)
+        cancelled_(false)
     {}
 
     ~Tier2GeneratorTaskImpl() override {
-        if (!finished_)
-            module_->notifyCompilationListeners();
+        module_->testingTier2Active_ = false;
     }
 
     void cancel() override {
         cancelled_ = true;
     }
 
     void execute() override {
-        MOZ_ASSERT(!finished_);
-        finished_ = CompileTier2(*compileArgs_, *module_, &cancelled_);
+        CompileTier2(*compileArgs_, *module_, &cancelled_);
     }
 };
 
 void
 Module::startTier2(const CompileArgs& args)
 {
-    MOZ_ASSERT(!tiering_.lock()->active);
-
-    // If a Module initiates tier-2 compilation, we must ensure that eventually
-    // notifyCompilationListeners() is called. Since we must ensure
-    // Tier2GeneratorTaskImpl objects are destroyed *anyway*, we use
-    // ~Tier2GeneratorTaskImpl() to call notifyCompilationListeners() if it
-    // hasn't been already.
+    MOZ_ASSERT(!testingTier2Active_);
 
     auto task = MakeUnique<Tier2GeneratorTaskImpl>(*this, args);
     if (!task)
         return;
 
-    tiering_.lock()->active = true;
+    // This flag will be cleared asynchronously by ~Tier2GeneratorTaskImpl()
+    // on success or failure.
+    testingTier2Active_ = true;
 
     StartOffThreadWasmTier2Generator(std::move(task));
 }
 
-void
-Module::notifyCompilationListeners()
-{
-    // Notify listeners without holding the lock to avoid deadlocks if the
-    // listener takes their own lock or reenters this Module.
-
-    Tiering::ListenerVector listeners;
-    {
-        auto tiering = tiering_.lock();
-
-        MOZ_ASSERT(tiering->active);
-        tiering->active = false;
-
-        Swap(listeners, tiering->listeners);
-
-        tiering.notify_all(/* inactive */);
-    }
-
-    for (RefPtr<JS::WasmModuleListener>& listener : listeners)
-        listener->onCompilationComplete();
-}
-
 bool
 Module::finishTier2(UniqueLinkDataTier linkData2, UniqueCodeTier tier2Arg, ModuleEnvironment* env2)
 {
     MOZ_ASSERT(code().bestTier() == Tier::Baseline && tier2Arg->tier() == Tier::Ion);
 
     // Install the data in the data structures. They will not be visible
     // until commitTier2().
 
@@ -291,24 +261,18 @@ Module::finishTier2(UniqueLinkDataTier l
         if (!stubs2->createTier2(gcTypesEnabled, funcExportIndices, tier2, &stub2Index))
             return false;
 
         // Now that we can't fail or otherwise abort tier2, make it live.
 
         MOZ_ASSERT(!code().hasTier2());
         code().commitTier2();
 
-        // Now tier2 is committed and we can update jump tables entries to
-        // start making tier2 live.  Because lazy stubs are protected by a lock
-        // and notifyCompilationListeners should be called without any lock
-        // held, do it before.
-
         stubs2->setJitEntries(stub2Index, code());
     }
-    notifyCompilationListeners();
 
     // And we update the jump vector.
 
     uint8_t* base = code().segment(Tier::Ion).base();
     for (const CodeRange& cr : metadata(Tier::Ion).codeRanges) {
         // These are racy writes that we just want to be visible, atomically,
         // eventually.  All hardware we care about will do this right.  But
         // we depend on the compiler not splitting the stores hidden inside the
@@ -318,75 +282,26 @@ Module::finishTier2(UniqueLinkDataTier l
         else if (cr.isJitEntry())
             code().setJitEntry(cr.funcIndex(), base + cr.begin());
     }
 
     return true;
 }
 
 void
-Module::blockOnTier2Complete() const
-{
-    auto tiering = tiering_.lock();
-    while (tiering->active)
-        tiering.wait(/* inactive */);
-}
-
-/* virtual */ size_t
-Module::bytecodeSerializedSize() const
-{
-    return bytecode_->bytes.length();
-}
-
-/* virtual */ void
-Module::bytecodeSerialize(uint8_t* bytecodeBegin, size_t bytecodeSize) const
+Module::testingBlockOnTier2Complete() const
 {
-    MOZ_ASSERT(!!bytecodeBegin == !!bytecodeSize);
-
-    // Bytecode deserialization is not guarded by Assumptions and thus must not
-    // change incompatibly between builds. For simplicity, the format of the
-    // bytecode file is a .wasm file which ensures backwards compatibility.
-
-    const Bytes& bytes = bytecode_->bytes;
-    uint8_t* bytecodeEnd = WriteBytes(bytecodeBegin, bytes.begin(), bytes.length());
-    MOZ_RELEASE_ASSERT(bytecodeEnd == bytecodeBegin + bytecodeSize);
-}
-
-/* virtual */ bool
-Module::compilationComplete() const
-{
-    // For the purposes of serialization, if there is not an active tier-2
-    // compilation in progress, compilation is "complete" in that
-    // compiledSerialize() can be called. N