Merge mozilla-inbound to mozilla-central. a=merge
authorAndreea Pavel <apavel@mozilla.com>
Fri, 13 Jul 2018 00:51:26 +0300
changeset 426408 96c61b1dd0a1ecbc37fd4e257ff0bdff6f56df8b
parent 426326 ccdb64ade35f4391813bfec4bd93e7c6562d99cd (current diff)
parent 426407 b93e0b5846d7d27d213dc7818d028be41a985264 (diff)
child 426422 46ef7ca5a86b486b826d3bc4abcdad16aa01fb28
child 426447 9cb2150c941b225cf14af83ec18613d43ff32868
push id34271
push userapavel@mozilla.com
push dateThu, 12 Jul 2018 21:52:15 +0000
treeherdermozilla-central@96c61b1dd0a1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
96c61b1dd0a1 / 63.0a1 / 20180712220034 / files
nightly linux64
96c61b1dd0a1 / 63.0a1 / 20180712220034 / files
nightly mac
96c61b1dd0a1 / 63.0a1 / 20180712220034 / files
nightly win32
96c61b1dd0a1 / 63.0a1 / 20180712220034 / files
nightly win64
96c61b1dd0a1 / 63.0a1 / 20180712220034 / 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 mozilla-inbound to mozilla-central. a=merge
docshell/base/nsIDocShellLoadInfo.idl
dom/base/nsDOMWindowUtils.cpp
dom/base/nsFrameLoader.cpp
dom/chrome-webidl/MessageManager.webidl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
layout/generic/nsFlexContainerFrame.cpp
media/libaom/config/generic/aom_config.asm
media/libaom/config/generic/aom_config.h
media/libaom/config/generic/aom_dsp_rtcd.h
media/libaom/config/generic/av1_rtcd.h
media/libaom/config/linux/arm/aom_config.asm
media/libaom/config/linux/arm/aom_config.h
media/libaom/config/linux/arm/aom_dsp_rtcd.h
media/libaom/config/linux/arm/av1_rtcd.h
media/libaom/config/linux/ia32/aom_config.asm
media/libaom/config/linux/ia32/aom_config.h
media/libaom/config/linux/ia32/aom_dsp_rtcd.h
media/libaom/config/linux/ia32/av1_rtcd.h
media/libaom/config/linux/x64/aom_config.asm
media/libaom/config/linux/x64/aom_config.h
media/libaom/config/linux/x64/aom_dsp_rtcd.h
media/libaom/config/linux/x64/av1_rtcd.h
media/libaom/config/mac/x64/aom_config.asm
media/libaom/config/mac/x64/aom_config.h
media/libaom/config/mac/x64/aom_dsp_rtcd.h
media/libaom/config/mac/x64/av1_rtcd.h
media/libaom/config/win/ia32/aom_config.asm
media/libaom/config/win/ia32/aom_config.c
media/libaom/config/win/ia32/aom_config.h
media/libaom/config/win/ia32/aom_dsp_rtcd.h
media/libaom/config/win/ia32/av1_rtcd.h
media/libaom/config/win/mingw32/aom_config.asm
media/libaom/config/win/mingw32/aom_config.h
media/libaom/config/win/mingw32/aom_dsp_rtcd.h
media/libaom/config/win/mingw32/av1_rtcd.h
media/libaom/config/win/x64/aom_config.asm
media/libaom/config/win/x64/aom_config.c
media/libaom/config/win/x64/aom_config.h
media/libaom/config/win/x64/aom_dsp_rtcd.h
media/libaom/config/win/x64/av1_rtcd.h
third_party/aom/README
third_party/aom/aom_dsp/aom_dsp.mk
third_party/aom/aom_dsp/arm/avg_neon.c
third_party/aom/aom_dsp/arm/idct16x16_1_add_neon_asm.asm
third_party/aom/aom_dsp/arm/idct16x16_add_neon_asm.asm
third_party/aom/aom_dsp/arm/idct32x32_1_add_neon_asm.asm
third_party/aom/aom_dsp/arm/idct32x32_add_neon_asm.asm
third_party/aom/aom_dsp/arm/idct4x4_1_add_neon_asm.asm
third_party/aom/aom_dsp/arm/idct4x4_add_neon_asm.asm
third_party/aom/aom_dsp/arm/idct8x8_1_add_neon_asm.asm
third_party/aom/aom_dsp/arm/idct8x8_add_neon_asm.asm
third_party/aom/aom_dsp/arm/intrapred_neon_asm.asm
third_party/aom/aom_dsp/arm/loopfilter_16_neon_asm.asm
third_party/aom/aom_dsp/arm/loopfilter_4_neon_asm.asm
third_party/aom/aom_dsp/arm/loopfilter_8_neon_asm.asm
third_party/aom/aom_dsp/avg.c
third_party/aom/aom_dsp/fwd_txfm.h
third_party/aom/aom_dsp/inv_txfm.c
third_party/aom/aom_dsp/inv_txfm.h
third_party/aom/aom_dsp/mips/convolve8_avg_dspr2.c
third_party/aom/aom_dsp/mips/fwd_dct32x32_msa.c
third_party/aom/aom_dsp/mips/fwd_txfm_msa.c
third_party/aom/aom_dsp/mips/inv_txfm_dspr2.h
third_party/aom/aom_dsp/prob.c
third_party/aom/aom_dsp/x86/aom_highbd_convolve_hip_ssse3.c
third_party/aom/aom_dsp/x86/avg_intrin_sse2.c
third_party/aom/aom_dsp/x86/fwd_txfm_avx2.h
third_party/aom/aom_dsp/x86/highbd_intrapred_avx2.c
third_party/aom/aom_dsp/x86/intrapred_ssse3_asm.asm
third_party/aom/aom_dsp/x86/inv_txfm_common_avx2.h
third_party/aom/aom_dsp/x86/inv_txfm_sse2.c
third_party/aom/aom_dsp/x86/inv_txfm_sse2.h
third_party/aom/aom_dsp/x86/txfm_common_avx2.h
third_party/aom/aom_dsp/x86/txfm_common_intrin.h
third_party/aom/aomdec.c
third_party/aom/aomenc.c
third_party/aom/aomstats.h
third_party/aom/args.c
third_party/aom/args.h
third_party/aom/av1/av1_common.mk
third_party/aom/av1/av1_cx.mk
third_party/aom/av1/av1_dx.mk
third_party/aom/av1/common/arm/neon/iht4x4_add_neon.c
third_party/aom/av1/common/arm/neon/iht8x8_add_neon.c
third_party/aom/av1/common/av1_fwd_txfm1d.c
third_party/aom/av1/common/av1_fwd_txfm1d.h
third_party/aom/av1/common/av1_fwd_txfm1d_cfg.h
third_party/aom/av1/common/av1_fwd_txfm2d.c
third_party/aom/av1/common/clpf.c
third_party/aom/av1/common/clpf_simd.h
third_party/aom/av1/common/daala_tx.c
third_party/aom/av1/common/daala_tx.h
third_party/aom/av1/common/generic_code.c
third_party/aom/av1/common/generic_code.h
third_party/aom/av1/common/mips/msa/av1_idct16x16_msa.c
third_party/aom/av1/common/mips/msa/av1_idct4x4_msa.c
third_party/aom/av1/common/mips/msa/av1_idct8x8_msa.c
third_party/aom/av1/common/pvq.c
third_party/aom/av1/common/pvq.h
third_party/aom/av1/common/x86/av1_convolve_ssse3.c
third_party/aom/av1/common/x86/av1_fwd_txfm1d_sse4.c
third_party/aom/av1/common/x86/av1_fwd_txfm2d_sse4.c
third_party/aom/av1/common/x86/av1_txfm1d_sse4.h
third_party/aom/av1/common/x86/highbd_warp_plane_ssse3.c
third_party/aom/av1/common/x86/hybrid_inv_txfm_avx2.c
third_party/aom/av1/common/x86/idct_intrin_sse2.c
third_party/aom/av1/common/x86/warp_plane_sse2.c
third_party/aom/av1/common/x86/warp_plane_ssse3.c
third_party/aom/av1/decoder/laplace_decoder.c
third_party/aom/av1/encoder/bgsprite.c
third_party/aom/av1/encoder/daala_compat_enc.c
third_party/aom/av1/encoder/dct.c
third_party/aom/av1/encoder/pvq_encoder.c
third_party/aom/av1/encoder/subexp.c
third_party/aom/av1/encoder/subexp.h
third_party/aom/av1/encoder/x86/dct_intrin_sse2.c
third_party/aom/av1/encoder/x86/hybrid_fwd_txfm_avx2.c
third_party/aom/build/cmake/aom_config.c.cmake
third_party/aom/build/make/Android.mk
third_party/aom/build/make/configure.sh
third_party/aom/build/make/gen_msvs_sln.sh
third_party/aom/build/make/gen_msvs_vcxproj.sh
third_party/aom/build/make/version.sh
third_party/aom/configure
third_party/aom/examples.mk
third_party/aom/libs.mk
third_party/aom/md5_utils.h
third_party/aom/rate_hist.h
third_party/aom/test/active_map_refresh_test.cc
third_party/aom/test/ans_codec_test.cc
third_party/aom/test/ans_test.cc
third_party/aom/test/av1_convolve_optimz_test.cc
third_party/aom/test/av1_convolve_test.cc
third_party/aom/test/av1_dct_test.cc
third_party/aom/test/av1_fht16x16_test.cc
third_party/aom/test/av1_fht16x32_test.cc
third_party/aom/test/av1_fht16x8_test.cc
third_party/aom/test/av1_fht32x16_test.cc
third_party/aom/test/av1_fht32x32_test.cc
third_party/aom/test/av1_fht4x4_test.cc
third_party/aom/test/av1_fht4x8_test.cc
third_party/aom/test/av1_fht64x64_test.cc
third_party/aom/test/av1_fht8x16_test.cc
third_party/aom/test/av1_fht8x4_test.cc
third_party/aom/test/av1_fht8x8_test.cc
third_party/aom/test/av1_inv_txfm_test.cc
third_party/aom/test/avg_test.cc
third_party/aom/test/clpf_test.cc
third_party/aom/test/dct16x16_test.cc
third_party/aom/test/dct32x32_test.cc
third_party/aom/test/dering_test.cc
third_party/aom/test/encoder_parms_get_to_decoder.cc
third_party/aom/test/fdct4x4_test.cc
third_party/aom/test/fdct8x8_test.cc
third_party/aom/test/level_test.cc
third_party/aom/test/lpf_8_test.cc
third_party/aom/test/minmax_test.cc
third_party/aom/test/partial_idct_test.cc
third_party/aom/test/realtime_test.cc
third_party/aom/test/test-data.mk
third_party/aom/test/test.mk
third_party/aom/test/user_priv_test.cc
third_party/aom/tools/build_inspector.sh
third_party/aom/tools_common.c
third_party/aom/tools_common.h
third_party/aom/warnings.h
third_party/aom/webmenc.h
third_party/aom/y4minput.c
third_party/aom/y4minput.h
toolkit/modules/Memory.jsm
--- a/browser/app/winlauncher/DllBlocklistWin.cpp
+++ b/browser/app/winlauncher/DllBlocklistWin.cpp
@@ -6,19 +6,29 @@
 
 #include "NativeNt.h"
 #include "nsWindowsDllInterceptor.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Types.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
+#define MOZ_LITERAL_UNICODE_STRING(s) \
+  { \
+    /* Length of the string in bytes, less the null terminator */ \
+    sizeof(s) - sizeof(wchar_t), \
+    /* Length of the string in bytes, including the null terminator */ \
+    sizeof(s), \
+    /* Pointer to the buffer */ \
+    const_cast<wchar_t*>(s) \
+  }
+
 #define DLL_BLOCKLIST_ENTRY(name, ...) \
-  { L##name, __VA_ARGS__ },
-#define DLL_BLOCKLIST_CHAR_TYPE wchar_t
+  { 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)
 #include "mozilla/WindowsDllBlocklistDefs.h"
 #else
 #include "mozilla/WindowsDllBlocklistCommon.h"
 DLL_BLOCKLIST_DEFINITIONS_BEGIN
 DLL_BLOCKLIST_DEFINITIONS_END
@@ -29,72 +39,72 @@ extern uint32_t gBlocklistInitFlags;
 static const HANDLE kCurrentProcess = reinterpret_cast<HANDLE>(-1);
 
 class MOZ_STATIC_CLASS MOZ_TRIVIAL_CTOR_DTOR NativeNtBlockSet final
 {
   struct NativeNtBlockSetEntry
   {
     NativeNtBlockSetEntry() = default;
     ~NativeNtBlockSetEntry() = default;
-    NativeNtBlockSetEntry(const wchar_t* aName, uint64_t aVersion,
+    NativeNtBlockSetEntry(const UNICODE_STRING& aName, uint64_t aVersion,
                           NativeNtBlockSetEntry* aNext)
       : mName(aName)
       , mVersion(aVersion)
       , mNext(aNext)
     {}
-    const wchar_t*          mName;
+    UNICODE_STRING          mName;
     uint64_t                mVersion;
     NativeNtBlockSetEntry*  mNext;
   };
 
 public:
   // Constructor and destructor MUST be trivial
   NativeNtBlockSet() = default;
   ~NativeNtBlockSet() = default;
 
-  void Add(const wchar_t* aName, uint64_t aVersion);
+  void Add(const UNICODE_STRING& aName, uint64_t aVersion);
   void Write(HANDLE aFile);
 
 private:
-  static NativeNtBlockSetEntry* NewEntry(const wchar_t* aName, uint64_t aVersion,
+  static NativeNtBlockSetEntry* NewEntry(const UNICODE_STRING& aName,
+                                         uint64_t aVersion,
                                          NativeNtBlockSetEntry* aNextEntry);
 
 private:
   NativeNtBlockSetEntry* mFirstEntry;
   // SRWLOCK_INIT == 0, so this is okay to use without any additional work as
   // long as NativeNtBlockSet is instantiated statically
   SRWLOCK                mLock;
 };
 
 NativeNtBlockSet::NativeNtBlockSetEntry*
-NativeNtBlockSet::NewEntry(const wchar_t* aName, uint64_t aVersion,
+NativeNtBlockSet::NewEntry(const UNICODE_STRING& aName, uint64_t aVersion,
                            NativeNtBlockSet::NativeNtBlockSetEntry* aNextEntry)
 {
   HANDLE processHeap = mozilla::nt::RtlGetProcessHeap();
   if (!processHeap) {
     return nullptr;
   }
 
   PVOID memory = ::RtlAllocateHeap(processHeap, 0, sizeof(NativeNtBlockSetEntry));
   if (!memory) {
     return nullptr;
   }
 
   return new (memory) NativeNtBlockSetEntry(aName, aVersion, aNextEntry);
 }
 
 void
-NativeNtBlockSet::Add(const wchar_t* aName, uint64_t aVersion)
+NativeNtBlockSet::Add(const UNICODE_STRING& aName, uint64_t aVersion)
 {
   ::RtlAcquireSRWLockExclusive(&mLock);
 
   for (NativeNtBlockSetEntry* entry = mFirstEntry; entry; entry = entry->mNext) {
-    // We just need to compare the string pointers, not the strings themselves,
-    // as we always pass in the strings statically defined in the blocklist.
-    if (aName == entry->mName && aVersion == entry->mVersion) {
+    if (::RtlEqualUnicodeString(&entry->mName, &aName, TRUE) &&
+        aVersion == entry->mVersion) {
       ::RtlReleaseSRWLockExclusive(&mLock);
       return;
     }
   }
 
   // Not present, add it
   NativeNtBlockSetEntry* newEntry = NewEntry(aName, aVersion, mFirstEntry);
   mFirstEntry = newEntry;
@@ -113,18 +123,19 @@ NativeNtBlockSet::Write(HANDLE aFile)
   // It would be nicer to use RAII here. However, its destructor
   // might not run if an exception occurs, in which case we would never release
   // the lock (MSVC warns about this possibility). So we acquire and release
   // manually.
   ::AcquireSRWLockExclusive(&mLock);
 
   MOZ_SEH_TRY {
     for (auto entry = mFirstEntry; entry; entry = entry->mNext) {
-      int convOk = ::WideCharToMultiByte(CP_UTF8, 0, entry->mName, -1, buf,
-                                         sizeof(buf), nullptr, nullptr);
+      int convOk = ::WideCharToMultiByte(CP_UTF8, 0, entry->mName.Buffer,
+                                         entry->mName.Length / sizeof(wchar_t),
+                                         buf, sizeof(buf), nullptr, nullptr);
       if (!convOk) {
         continue;
       }
 
       // write name[,v.v.v.v];
       if (!WriteFile(aFile, buf, convOk, &nBytes, nullptr)) {
         continue;
       }
@@ -220,29 +231,29 @@ CheckBlockInfo(const DllBlockInfo* aInfo
 static bool
 IsDllAllowed(const UNICODE_STRING& aLeafName, void* aBaseAddress)
 {
   if (mozilla::nt::Contains12DigitHexString(aLeafName) ||
       mozilla::nt::IsFileNameAtLeast16HexDigits(aLeafName)) {
     return false;
   }
 
-  UNICODE_STRING testStr;
   DECLARE_POINTER_TO_FIRST_DLL_BLOCKLIST_ENTRY(info);
-  while (info->name) {
-    ::RtlInitUnicodeString(&testStr, info->name);
-    if (::RtlEqualUnicodeString(&aLeafName, &testStr, TRUE)) {
+  DECLARE_POINTER_TO_LAST_DLL_BLOCKLIST_ENTRY(end);
+
+  while (info < end) {
+    if (::RtlEqualUnicodeString(&aLeafName, &info->name, TRUE)) {
       break;
     }
 
     ++info;
   }
 
   uint64_t version;
-  if (info->name && !CheckBlockInfo(info, aBaseAddress, version)) {
+  if (info->name.Length && !CheckBlockInfo(info, aBaseAddress, version)) {
     gBlockSet.Add(info->name, version);
     return false;
   }
 
   return true;
 }
 
 typedef decltype(&NtMapViewOfSection) NtMapViewOfSection_func;
--- a/browser/app/winlauncher/NativeNt.h
+++ b/browser/app/winlauncher/NativeNt.h
@@ -143,16 +143,23 @@ MatchUnicodeString(const UNICODE_STRING&
   }
 
   return true;
 }
 
 inline bool
 Contains12DigitHexString(const UNICODE_STRING& aLeafName)
 {
+  // Quick check: If the string is too short, don't bother
+  // (We need at least 12 hex digits, one char for '.', and 3 for extension)
+  const USHORT kMinLen = (12 + 1 + 3) * sizeof(wchar_t);
+  if (aLeafName.Length < kMinLen) {
+    return false;
+  }
+
   uint16_t start, end;
   if (!FindCharInUnicodeString(aLeafName, L'.', start)) {
     return false;
   }
 
   ++start;
   if (!FindCharInUnicodeString(aLeafName, L'.', end, start)) {
     return false;
@@ -168,16 +175,23 @@ Contains12DigitHexString(const UNICODE_S
   test.MaximumLength = test.Length;
 
   return MatchUnicodeString(test, &IsHexDigit);
 }
 
 inline bool
 IsFileNameAtLeast16HexDigits(const UNICODE_STRING& aLeafName)
 {
+  // Quick check: If the string is too short, don't bother
+  // (We need 16 hex digits, one char for '.', and 3 for extension)
+  const USHORT kMinLen = (16 + 1 + 3) * sizeof(wchar_t);
+  if (aLeafName.Length < kMinLen) {
+    return false;
+  }
+
   uint16_t dotIndex;
   if (!FindCharInUnicodeString(aLeafName, L'.', dotIndex)) {
     return false;
   }
 
   if (dotIndex < 16) {
     return false;
   }
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -7268,68 +7268,16 @@ exports.CSS_PROPERTIES = {
       "inherit",
       "initial",
       "left",
       "right",
       "top",
       "unset"
     ]
   },
-  "offset-block-end": {
-    "isInherited": false,
-    "subproperties": [
-      "inset-block-end"
-    ],
-    "supports": [],
-    "values": [
-      "auto",
-      "inherit",
-      "initial",
-      "unset"
-    ]
-  },
-  "offset-block-start": {
-    "isInherited": false,
-    "subproperties": [
-      "inset-block-start"
-    ],
-    "supports": [],
-    "values": [
-      "auto",
-      "inherit",
-      "initial",
-      "unset"
-    ]
-  },
-  "offset-inline-end": {
-    "isInherited": false,
-    "subproperties": [
-      "inset-inline-end"
-    ],
-    "supports": [],
-    "values": [
-      "auto",
-      "inherit",
-      "initial",
-      "unset"
-    ]
-  },
-  "offset-inline-start": {
-    "isInherited": false,
-    "subproperties": [
-      "inset-inline-start"
-    ],
-    "supports": [],
-    "values": [
-      "auto",
-      "inherit",
-      "initial",
-      "unset"
-    ]
-  },
   "opacity": {
     "isInherited": false,
     "subproperties": [
       "opacity"
     ],
     "supports": [],
     "values": [
       "inherit",
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -36,17 +36,16 @@ DIRS += [
 ]
 
 XPIDL_SOURCES += [
     'nsCDefaultURIFixup.idl',
     'nsIClipboardCommands.idl',
     'nsIContentViewer.idl',
     'nsIContentViewerEdit.idl',
     'nsIDocShell.idl',
-    'nsIDocShellLoadInfo.idl',
     'nsIDocShellTreeItem.idl',
     'nsIDocShellTreeOwner.idl',
     'nsIDocumentLoaderFactory.idl',
     'nsIDownloadHistory.idl',
     'nsILoadContext.idl',
     'nsIPrivacyTransitionObserver.idl',
     'nsIReflowObserver.idl',
     'nsIRefreshURI.idl',
@@ -59,16 +58,17 @@ XPIDL_SOURCES += [
     'nsIWebNavigationInfo.idl',
     'nsIWebPageDescriptor.idl',
 ]
 
 XPIDL_MODULE = 'docshell'
 
 EXPORTS += [
     'nsCTooltipTextProvider.h',
+    'nsDocShellLoadInfo.h',
     'nsDocShellLoadTypes.h',
     'nsDocShellTreeOwner.h',
     'nsILinkHandler.h',
     'nsIScrollObserver.h',
     'nsIWebShellServices.h',
     'SerializedLoadContext.h',
 ]
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -651,17 +651,17 @@ nsDocShell::GetInterface(const nsIID& aI
   }
 
   NS_IF_ADDREF(((nsISupports*)*aSink));
   return *aSink ? NS_OK : NS_NOINTERFACE;
 }
 
 NS_IMETHODIMP
 nsDocShell::LoadURI(nsIURI* aURI,
-                    nsIDocShellLoadInfo* aLoadInfo,
+                    nsDocShellLoadInfo* aLoadInfo,
                     uint32_t aLoadFlags,
                     bool aFirstParty)
 {
   MOZ_ASSERT(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
              "Unexpected flags");
   MOZ_ASSERT((aLoadFlags & 0xf) == 0, "Should not have these flags set");
 
   // Note: we allow loads to get through here even if mFiredUnloadEvent is
@@ -700,40 +700,38 @@ nsDocShell::LoadURI(nsIURI* aURI,
 
   if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
       mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
     StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
   }
 
   // Extract the info from the DocShellLoadInfo struct...
   if (aLoadInfo) {
-    aLoadInfo->GetReferrer(getter_AddRefs(referrer));
-    aLoadInfo->GetOriginalURI(getter_AddRefs(originalURI));
-    GetMaybeResultPrincipalURI(aLoadInfo, resultPrincipalURI);
-    aLoadInfo->GetLoadReplace(&loadReplace);
-    nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
-    aLoadInfo->GetLoadType(&lt);
+    referrer = aLoadInfo->Referrer();
+    originalURI = aLoadInfo->OriginalURI();
+    aLoadInfo->GetMaybeResultPrincipalURI(resultPrincipalURI);
+    loadReplace = aLoadInfo->LoadReplace();
     // Get the appropriate loadType from nsIDocShellLoadInfo type
-    loadType = ConvertDocShellInfoLoadTypeToLoadType(lt);
-
-    aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
-    aLoadInfo->GetInheritPrincipal(&inheritPrincipal);
-    aLoadInfo->GetPrincipalIsExplicit(&principalIsExplicit);
-    aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
-    aLoadInfo->GetTarget(getter_Copies(target));
-    aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
-    aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
-    aLoadInfo->GetSendReferrer(&sendReferrer);
-    aLoadInfo->GetReferrerPolicy(&referrerPolicy);
-    aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
+    loadType = aLoadInfo->LoadType();
+
+    triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
+    inheritPrincipal = aLoadInfo->InheritPrincipal();
+    principalIsExplicit = aLoadInfo->PrincipalIsExplicit();
+    shEntry = aLoadInfo->SHEntry();
+    aLoadInfo->GetTarget(target);
+    postStream = aLoadInfo->PostDataStream();
+    headersStream = aLoadInfo->HeadersStream();
+    sendReferrer = aLoadInfo->SendReferrer();
+    referrerPolicy = aLoadInfo->ReferrerPolicy();
+    isSrcdoc = aLoadInfo->IsSrcdocLoad();
     aLoadInfo->GetSrcdocData(srcdoc);
-    aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
-    aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
-    aLoadInfo->GetForceAllowDataURI(&forceAllowDataURI);
-    aLoadInfo->GetOriginalFrameSrc(&originalFrameSrc);
+    sourceDocShell = aLoadInfo->SourceDocShell();
+    baseURI = aLoadInfo->BaseURI();
+    forceAllowDataURI = aLoadInfo->ForceAllowDataURI();
+    originalFrameSrc = aLoadInfo->OriginalFrameSrc();
   }
 
   MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
           ("nsDocShell[%p]: loading %s with flags 0x%08x",
            this, aURI->GetSpecOrDefault().get(), aLoadFlags));
 
   if (!shEntry &&
       !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
@@ -1019,26 +1017,16 @@ nsDocShell::LoadURI(nsIURI* aURI,
                       aFirstParty,
                       srcdoc,
                       sourceDocShell,
                       baseURI,
                       nullptr,  // No nsIDocShell
                       nullptr); // No nsIRequest
 }
 
-NS_IMETHODIMP
-nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo)
-{
-  nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo();
-  nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
-
-  localRef.forget(aLoadInfo);
-  return NS_OK;
-}
-
 /*
  * Reset state to a new content model within the current document and the
  * document viewer. Called by the document before initiating an out of band
  * document.write().
  */
 NS_IMETHODIMP
 nsDocShell::PrepareForNewContentModel()
 {
@@ -3721,31 +3709,29 @@ nsDocShell::GetChildSHEntry(int32_t aChi
      * loaded from history in certain situations.
      */
     bool parentExpired = false;
     mLSHE->GetExpirationStatus(&parentExpired);
 
     /* Get the parent's Load Type so that it can be set on the child too.
      * By default give a loadHistory value
      */
-    uint32_t loadType = nsIDocShellLoadInfo::loadHistory;
+    uint32_t loadType = LOAD_HISTORY;
     mLSHE->GetLoadType(&loadType);
     // If the user did a shift-reload on this frameset page,
     // we don't want to load the subframes from history.
-    if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
-        loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
-        loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
-        loadType == nsIDocShellLoadInfo::loadRefresh) {
+    if (IsForceReloadType(loadType) ||
+        loadType == LOAD_REFRESH) {
       return rv;
     }
 
     /* If the user pressed reload and the parent frame has expired
      *  from cache, we do not want to load the child frame from history.
      */
-    if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
+    if (parentExpired && (loadType == LOAD_RELOAD_NORMAL)) {
       // The parent has expired. Return null.
       *aResult = nullptr;
       return rv;
     }
 
     nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
     if (container) {
       // Get the child subframe from session history.
@@ -4223,37 +4209,33 @@ nsDocShell::LoadURIWithOptions(const cha
     aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
 
   // Don't pass certain flags that aren't needed and end up confusing
   // ConvertLoadTypeToDocShellInfoLoadType.  We do need to ensure that they are
   // passed to LoadURI though, since it uses them.
   uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
   aLoadFlags &= ~EXTRA_LOAD_FLAGS;
 
-  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
-  rv = CreateLoadInfo(getter_AddRefs(loadInfo));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
+  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
 
   /*
    * If the user "Disables Protection on This Page", we have to make sure to
    * remember the users decision when opening links in child tabs [Bug 906190]
    */
   uint32_t loadType;
   if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
     loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
   } else {
     loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
   }
 
-  loadInfo->SetLoadType(ConvertLoadTypeToDocShellInfoLoadType(loadType));
+  loadInfo->SetLoadType(loadType);
   loadInfo->SetPostDataStream(postStream);
   loadInfo->SetReferrer(aReferringURI);
-  loadInfo->SetReferrerPolicy(aReferrerPolicy);
+  loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
   loadInfo->SetHeadersStream(aHeaderStream);
   loadInfo->SetBaseURI(aBaseURI);
   loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
   loadInfo->SetForceAllowDataURI(forceAllowDataURI);
 
   if (fixupInfo) {
     nsAutoString searchProvider, keyword;
     fixupInfo->GetKeywordProviderName(searchProvider);
@@ -6185,19 +6167,17 @@ nsDocShell::ForceRefreshURIFromTimer(nsI
   return ForceRefreshURI(aURI, aPrincipal, aDelay, aMetaRefresh);
 }
 
 NS_IMETHODIMP
 nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDelay, bool aMetaRefresh)
 {
   NS_ENSURE_ARG(aURI);
 
-  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
-  CreateLoadInfo(getter_AddRefs(loadInfo));
-  NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
+  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
 
   /* We do need to pass in a referrer, but we don't want it to
    * be sent to the server.
    */
   loadInfo->SetSendReferrer(false);
 
   /* for most refreshes the current URI is an appropriate
    * internal referrer
@@ -6223,28 +6203,28 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI
   bool equalUri = false;
   nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
   if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
       aDelay <= REFRESH_REDIRECT_TIMER) {
     /* It is a META refresh based redirection within the threshold time
      * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
      * Pass a REPLACE flag to LoadURI().
      */
-    loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
+    loadInfo->SetLoadType(LOAD_NORMAL_REPLACE);
 
     /* for redirects we mimic HTTP, which passes the
      *  original referrer
      */
     nsCOMPtr<nsIURI> internalReferrer;
     GetReferringURI(getter_AddRefs(internalReferrer));
     if (internalReferrer) {
       loadInfo->SetReferrer(internalReferrer);
     }
   } else {
-    loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
+    loadInfo->SetLoadType(LOAD_REFRESH);
   }
 
   /*
    * LoadURI(...) will cancel all refresh timers... This causes the
    * Timer and its refreshData instance to be released...
    */
   LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, true);
 
@@ -7086,17 +7066,17 @@ nsDocShell::EndPageLoad(nsIWebProgress* 
       mLSHE->SetSaveLayoutStateFlag(false);
     }
   }
 
   // Clear mLSHE after calling the onLoadHandlers. This way, if the
   // onLoadHandler tries to load something different in
   // itself or one of its children, we can deal with it appropriately.
   if (mLSHE) {
-    mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
+    mLSHE->SetLoadType(LOAD_HISTORY);
 
     // Clear the mLSHE reference to indicate document loading is done one
     // way or another.
     SetHistoryEntry(&mLSHE, nullptr);
   }
   // if there's a refresh header in the channel, this method
   // will set it up for us.
   if (mIsActive || !mDisableMetaRefreshWhenInactive)
@@ -9420,38 +9400,34 @@ nsDocShell::InternalLoad(nsIURI* aURI,
         // If OnLinkClickSync was invoked inside the onload handler, the load
         // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
         // LOAD_LINK.
         MOZ_ASSERT(aLoadType == LOAD_LINK ||
                    aLoadType == LOAD_NORMAL_REPLACE);
         MOZ_ASSERT(!aSHEntry);
         MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this.
 
-        nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
-        rv = CreateLoadInfo(getter_AddRefs(loadInfo));
-        if (NS_FAILED(rv)) {
-          return rv;
-        }
+        RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
 
         // Set up our loadinfo so it will do the load as much like we would have
         // as possible.
         loadInfo->SetReferrer(aReferrer);
-        loadInfo->SetReferrerPolicy(aReferrerPolicy);
+        loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy);
         loadInfo->SetSendReferrer(!(aFlags &
                                     INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
         loadInfo->SetOriginalURI(aOriginalURI);
-        SetMaybeResultPrincipalURI(loadInfo, aResultPrincipalURI);
+        loadInfo->SetMaybeResultPrincipalURI(aResultPrincipalURI);
         loadInfo->SetLoadReplace(aLoadReplace);
         loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
         loadInfo->SetInheritPrincipal(
           aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
         // Explicit principal because we do not want any guesses as to what the
         // principal to inherit is: it should be aTriggeringPrincipal.
         loadInfo->SetPrincipalIsExplicit(true);
-        loadInfo->SetLoadType(ConvertLoadTypeToDocShellInfoLoadType(LOAD_LINK));
+        loadInfo->SetLoadType(LOAD_LINK);
         loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
 
         rv = win->Open(NS_ConvertUTF8toUTF16(spec),
                        aWindowTarget, // window name
                        EmptyString(), // Features
                        loadInfo,
                        true, // aForceNoOpener
                        getter_AddRefs(newWin));
@@ -10956,17 +10932,17 @@ nsDocShell::DoChannelLoad(nsIChannel* aC
   }
 
   if (!aBypassClassifier) {
     loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
   }
 
   // If the user pressed shift-reload, then do not allow ServiceWorker
   // interception to occur. See step 12.1 of the SW HandleFetch algorithm.
-  if (IsForceReloadType(mLoadType)) {
+  if (IsForceReloading()) {
     loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
   }
 
   (void)aChannel->SetLoadFlags(loadFlags);
 
   uint32_t openFlags = 0;
   if (mLoadType == LOAD_LINK) {
     openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
@@ -14212,8 +14188,14 @@ nsDocShell::GetColorMatrix(uint32_t* aMa
 
     MOZ_ASSERT(20 * sizeof(float) == sizeof(mColorMatrix->components));
     *aMatrixLen = 20;
     memcpy(*aMatrix, mColorMatrix->components, 20 * sizeof(float));
   }
 
   return NS_OK;
 }
+
+bool
+nsDocShell::IsForceReloading()
+{
+  return IsForceReloadType(mLoadType);
+}
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -19,17 +19,16 @@
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/dom/ChildSHistory.h"
 
 #include "nsIAuthPromptProvider.h"
 #include "nsIBaseWindow.h"
 #include "nsIClipboardCommands.h"
 #include "nsIDeprecationWarner.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDOMStorageManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILinkHandler.h"
 #include "nsILoadContext.h"
 #include "nsILoadURIDelegate.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIRefreshURI.h"
@@ -371,16 +370,20 @@ public:
                           nsIPrincipal* aLoadingPrincipal,
                           bool aInPrivateBrowsing);
 
   static nsDocShell* Cast(nsIDocShell* aDocShell)
   {
     return static_cast<nsDocShell*>(aDocShell);
   }
 
+  // Returns true if the current load is a force reload (started by holding
+  // shift while triggering reload)
+  bool IsForceReloading();
+
 private: // member functions
   friend class nsDSURIContentListener;
   friend class FramingChecker;
   friend class OnLinkClickEvent;
 
   // It is necessary to allow adding a timeline marker wherever a docshell
   // instance is available. This operation happens frequently and needs to
   // be very fast, so instead of using a Map or having to search for some
--- a/docshell/base/nsDocShellLoadInfo.cpp
+++ b/docshell/base/nsDocShellLoadInfo.cpp
@@ -6,405 +6,300 @@
 
 #include "nsDocShellLoadInfo.h"
 #include "nsISHEntry.h"
 #include "nsIInputStream.h"
 #include "nsIURI.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "mozilla/Unused.h"
+#include "mozilla/Maybe.h"
 
 namespace mozilla {
 
-void
-GetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>>& aRPURI)
-{
-  if (!aLoadInfo) {
-    return;
-  }
-
-  nsresult rv;
-
-  bool isSome;
-  rv = aLoadInfo->GetResultPrincipalURIIsSome(&isSome);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  aRPURI.reset();
-
-  if (!isSome) {
-    return;
-  }
-
-  nsCOMPtr<nsIURI> uri;
-  rv = aLoadInfo->GetResultPrincipalURI(getter_AddRefs(uri));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  aRPURI.emplace(std::move(uri));
-}
-
-void
-SetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>> const& aRPURI)
-{
-  if (!aLoadInfo) {
-    return;
-  }
-
-  nsresult rv;
-
-  rv = aLoadInfo->SetResultPrincipalURI(aRPURI.refOr(nullptr));
-  Unused << NS_WARN_IF(NS_FAILED(rv));
-
-  rv = aLoadInfo->SetResultPrincipalURIIsSome(aRPURI.isSome());
-  Unused << NS_WARN_IF(NS_FAILED(rv));
-}
 
 } // mozilla
 
 nsDocShellLoadInfo::nsDocShellLoadInfo()
   : mResultPrincipalURIIsSome(false)
   , mLoadReplace(false)
   , mInheritPrincipal(false)
   , mPrincipalIsExplicit(false)
   , mForceAllowDataURI(false)
   , mOriginalFrameSrc(false)
   , mSendReferrer(true)
   , mReferrerPolicy(mozilla::net::RP_Unset)
-  , mLoadType(nsIDocShellLoadInfo::loadNormal)
+  , mLoadType(LOAD_NORMAL)
   , mIsSrcdocLoad(false)
 {
 }
 
 nsDocShellLoadInfo::~nsDocShellLoadInfo()
 {
 }
 
-NS_IMPL_ADDREF(nsDocShellLoadInfo)
-NS_IMPL_RELEASE(nsDocShellLoadInfo)
-
-NS_INTERFACE_MAP_BEGIN(nsDocShellLoadInfo)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellLoadInfo)
-  NS_INTERFACE_MAP_ENTRY(nsIDocShellLoadInfo)
-NS_INTERFACE_MAP_END
-
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetReferrer(nsIURI** aReferrer)
+nsIURI*
+nsDocShellLoadInfo::Referrer() const
 {
-  NS_ENSURE_ARG_POINTER(aReferrer);
-
-  *aReferrer = mReferrer;
-  NS_IF_ADDREF(*aReferrer);
-  return NS_OK;
+  return mReferrer;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetReferrer(nsIURI* aReferrer)
 {
   mReferrer = aReferrer;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetOriginalURI(nsIURI** aOriginalURI)
+nsIURI*
+nsDocShellLoadInfo::OriginalURI() const
 {
-  NS_ENSURE_ARG_POINTER(aOriginalURI);
-
-  *aOriginalURI = mOriginalURI;
-  NS_IF_ADDREF(*aOriginalURI);
-  return NS_OK;
+  return mOriginalURI;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetOriginalURI(nsIURI* aOriginalURI)
 {
   mOriginalURI = aOriginalURI;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetResultPrincipalURI(nsIURI** aResultPrincipalURI)
+nsIURI*
+nsDocShellLoadInfo::ResultPrincipalURI() const
 {
-  NS_ENSURE_ARG_POINTER(aResultPrincipalURI);
-
-  *aResultPrincipalURI = mResultPrincipalURI;
-  NS_IF_ADDREF(*aResultPrincipalURI);
-  return NS_OK;
+  return mResultPrincipalURI;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetResultPrincipalURI(nsIURI* aResultPrincipalURI)
 {
   mResultPrincipalURI = aResultPrincipalURI;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetResultPrincipalURIIsSome(bool* aIsSome)
+bool
+nsDocShellLoadInfo::ResultPrincipalURIIsSome() const
 {
-  *aIsSome = mResultPrincipalURIIsSome;
-  return NS_OK;
+  return mResultPrincipalURIIsSome;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetResultPrincipalURIIsSome(bool aIsSome)
 {
   mResultPrincipalURIIsSome = aIsSome;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetLoadReplace(bool* aLoadReplace)
+bool
+nsDocShellLoadInfo::LoadReplace() const
 {
-  *aLoadReplace = mLoadReplace;
-  return NS_OK;
+  return mLoadReplace;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetLoadReplace(bool aLoadReplace)
 {
   mLoadReplace = aLoadReplace;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal)
+nsIPrincipal*
+nsDocShellLoadInfo::TriggeringPrincipal() const
 {
-  NS_ENSURE_ARG_POINTER(aTriggeringPrincipal);
-  NS_IF_ADDREF(*aTriggeringPrincipal = mTriggeringPrincipal);
-  return NS_OK;
+  return mTriggeringPrincipal;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal)
 {
   mTriggeringPrincipal = aTriggeringPrincipal;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetInheritPrincipal(bool* aInheritPrincipal)
+bool
+nsDocShellLoadInfo::InheritPrincipal() const
 {
-  NS_ENSURE_ARG_POINTER(aInheritPrincipal);
-  *aInheritPrincipal = mInheritPrincipal;
-  return NS_OK;
+  return mInheritPrincipal;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetInheritPrincipal(bool aInheritPrincipal)
 {
   mInheritPrincipal = aInheritPrincipal;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetPrincipalIsExplicit(bool* aPrincipalIsExplicit)
+bool
+nsDocShellLoadInfo::PrincipalIsExplicit() const
 {
-  *aPrincipalIsExplicit = mPrincipalIsExplicit;
-  return NS_OK;
+  return mPrincipalIsExplicit;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetPrincipalIsExplicit(bool aPrincipalIsExplicit)
 {
   mPrincipalIsExplicit = aPrincipalIsExplicit;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetForceAllowDataURI(bool* aForceAllowDataURI)
+bool
+nsDocShellLoadInfo::ForceAllowDataURI() const
 {
-  *aForceAllowDataURI = mForceAllowDataURI;
-  return NS_OK;
+  return mForceAllowDataURI;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI)
 {
   mForceAllowDataURI = aForceAllowDataURI;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetOriginalFrameSrc(bool* aOriginalFrameSrc)
+bool
+nsDocShellLoadInfo::OriginalFrameSrc() const
 {
-  *aOriginalFrameSrc = mOriginalFrameSrc;
-  return NS_OK;
+  return mOriginalFrameSrc;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetOriginalFrameSrc(bool aOriginalFrameSrc)
 {
   mOriginalFrameSrc = aOriginalFrameSrc;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType* aLoadType)
+uint32_t
+nsDocShellLoadInfo::LoadType() const
 {
-  NS_ENSURE_ARG_POINTER(aLoadType);
-
-  *aLoadType = mLoadType;
-  return NS_OK;
+  return mLoadType;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::SetLoadType(nsDocShellInfoLoadType aLoadType)
+void
+nsDocShellLoadInfo::SetLoadType(uint32_t aLoadType)
 {
   mLoadType = aLoadType;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetSHEntry(nsISHEntry** aSHEntry)
+nsISHEntry*
+nsDocShellLoadInfo::SHEntry() const
 {
-  NS_ENSURE_ARG_POINTER(aSHEntry);
-
-  *aSHEntry = mSHEntry;
-  NS_IF_ADDREF(*aSHEntry);
-  return NS_OK;
+  return mSHEntry;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetSHEntry(nsISHEntry* aSHEntry)
 {
   mSHEntry = aSHEntry;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetTarget(char16_t** aTarget)
+void
+nsDocShellLoadInfo::GetTarget(nsAString& aTarget) const
 {
-  NS_ENSURE_ARG_POINTER(aTarget);
-
-  *aTarget = ToNewUnicode(mTarget);
-
-  return NS_OK;
+  aTarget = mTarget;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::SetTarget(const char16_t* aTarget)
+void
+nsDocShellLoadInfo::SetTarget(const nsAString& aTarget)
 {
-  mTarget.Assign(aTarget);
-  return NS_OK;
+  mTarget = aTarget;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetPostDataStream(nsIInputStream** aResult)
+nsIInputStream*
+nsDocShellLoadInfo::PostDataStream() const
 {
-  NS_ENSURE_ARG_POINTER(aResult);
-
-  *aResult = mPostDataStream;
-
-  NS_IF_ADDREF(*aResult);
-  return NS_OK;
+  return mPostDataStream;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetPostDataStream(nsIInputStream* aStream)
 {
   mPostDataStream = aStream;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetHeadersStream(nsIInputStream** aHeadersStream)
+nsIInputStream*
+nsDocShellLoadInfo::HeadersStream() const
 {
-  NS_ENSURE_ARG_POINTER(aHeadersStream);
-  *aHeadersStream = mHeadersStream;
-  NS_IF_ADDREF(*aHeadersStream);
-  return NS_OK;
+  return mHeadersStream;
 }
-NS_IMETHODIMP
+
+void
 nsDocShellLoadInfo::SetHeadersStream(nsIInputStream* aHeadersStream)
 {
   mHeadersStream = aHeadersStream;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetSendReferrer(bool* aSendReferrer)
+bool
+nsDocShellLoadInfo::SendReferrer() const
 {
-  NS_ENSURE_ARG_POINTER(aSendReferrer);
-
-  *aSendReferrer = mSendReferrer;
-  return NS_OK;
+  return mSendReferrer;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetSendReferrer(bool aSendReferrer)
 {
   mSendReferrer = aSendReferrer;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetReferrerPolicy(
-    nsDocShellInfoReferrerPolicy* aReferrerPolicy)
+uint32_t
+nsDocShellLoadInfo::ReferrerPolicy() const
 {
-  *aReferrerPolicy = mReferrerPolicy;
-  return NS_OK;
+  return mReferrerPolicy;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::SetReferrerPolicy(
-    nsDocShellInfoReferrerPolicy aReferrerPolicy)
+void
+nsDocShellLoadInfo::SetReferrerPolicy(mozilla::net::ReferrerPolicy aReferrerPolicy)
 {
   mReferrerPolicy = aReferrerPolicy;
-  return NS_OK;
+}
+
+bool
+nsDocShellLoadInfo::IsSrcdocLoad() const
+{
+  return mIsSrcdocLoad;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetIsSrcdocLoad(bool* aIsSrcdocLoad)
+void
+nsDocShellLoadInfo::GetSrcdocData(nsAString& aSrcdocData) const
 {
-  *aIsSrcdocLoad = mIsSrcdocLoad;
-  return NS_OK;
+  aSrcdocData = mSrcdocData;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetSrcdocData(nsAString& aSrcdocData)
-{
-  aSrcdocData = mSrcdocData;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetSrcdocData(const nsAString& aSrcdocData)
 {
   mSrcdocData = aSrcdocData;
   mIsSrcdocLoad = true;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetSourceDocShell(nsIDocShell** aSourceDocShell)
+nsIDocShell*
+nsDocShellLoadInfo::SourceDocShell() const
 {
-  MOZ_ASSERT(aSourceDocShell);
-  nsCOMPtr<nsIDocShell> result = mSourceDocShell;
-  result.forget(aSourceDocShell);
-  return NS_OK;
+  return mSourceDocShell;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetSourceDocShell(nsIDocShell* aSourceDocShell)
 {
   mSourceDocShell = aSourceDocShell;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShellLoadInfo::GetBaseURI(nsIURI** aBaseURI)
+nsIURI*
+nsDocShellLoadInfo::BaseURI() const
 {
-  NS_ENSURE_ARG_POINTER(aBaseURI);
-
-  *aBaseURI = mBaseURI;
-  NS_IF_ADDREF(*aBaseURI);
-  return NS_OK;
+  return mBaseURI;
 }
 
-NS_IMETHODIMP
+void
 nsDocShellLoadInfo::SetBaseURI(nsIURI* aBaseURI)
 {
   mBaseURI = aBaseURI;
-  return NS_OK;
 }
+
+void
+nsDocShellLoadInfo::GetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>>& aRPURI) const
+{
+  bool isSome = ResultPrincipalURIIsSome();
+  aRPURI.reset();
+
+  if (!isSome) {
+    return;
+  }
+
+  nsCOMPtr<nsIURI> uri = ResultPrincipalURI();
+  aRPURI.emplace(std::move(uri));
+}
+
+void
+nsDocShellLoadInfo::SetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI)
+{
+  SetResultPrincipalURI(aRPURI.refOr(nullptr));
+  SetResultPrincipalURIIsSome(aRPURI.isSome());
+}
--- a/docshell/base/nsDocShellLoadInfo.h
+++ b/docshell/base/nsDocShellLoadInfo.h
@@ -5,53 +5,201 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsDocShellLoadInfo_h__
 #define nsDocShellLoadInfo_h__
 
 // Helper Classes
 #include "nsCOMPtr.h"
 #include "nsString.h"
-
-// Interfaces Needed
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadTypes.h"
 
 class nsIInputStream;
 class nsISHEntry;
 class nsIURI;
 class nsIDocShell;
 
-class nsDocShellLoadInfo : public nsIDocShellLoadInfo
+/**
+ * nsDocShellLoadInfo contains setup information used in a nsIDocShell::loadURI
+ * call.
+ */
+class nsDocShellLoadInfo
 {
 public:
+  NS_INLINE_DECL_REFCOUNTING(nsDocShellLoadInfo);
+
   nsDocShellLoadInfo();
 
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOCSHELLLOADINFO
+  nsIURI* Referrer() const;
+
+  void SetReferrer(nsIURI* aReferrer);
+
+  nsIURI* OriginalURI() const;
+
+  void SetOriginalURI(nsIURI* aOriginalURI);
+
+  nsIURI* ResultPrincipalURI() const;
+
+  void SetResultPrincipalURI(nsIURI* aResultPrincipalURI);
+
+  bool ResultPrincipalURIIsSome() const;
+
+  void SetResultPrincipalURIIsSome(bool aIsSome);
+
+  bool LoadReplace() const;
+
+  void SetLoadReplace(bool aLoadReplace);
+
+  nsIPrincipal* TriggeringPrincipal() const;
+
+  void SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal);
+
+  bool InheritPrincipal() const;
+
+  void SetInheritPrincipal(bool aInheritPrincipal);
+
+  bool PrincipalIsExplicit() const;
+
+  void SetPrincipalIsExplicit(bool aPrincipalIsExplicit);
+
+  bool ForceAllowDataURI() const;
+
+  void SetForceAllowDataURI(bool aForceAllowDataURI);
+
+  bool OriginalFrameSrc() const;
+
+  void SetOriginalFrameSrc(bool aOriginalFrameSrc);
+
+  uint32_t LoadType() const;
+
+  void SetLoadType(uint32_t aLoadType);
+
+  nsISHEntry* SHEntry() const;
+
+  void SetSHEntry(nsISHEntry* aSHEntry);
+
+  void GetTarget(nsAString& aTarget) const;
+
+  void SetTarget(const nsAString& aTarget);
+
+  nsIInputStream* PostDataStream() const;
+
+  void SetPostDataStream(nsIInputStream* aStream);
+
+  nsIInputStream* HeadersStream() const;
+
+  void SetHeadersStream(nsIInputStream* aHeadersStream);
+
+  bool SendReferrer() const;
+
+  void SetSendReferrer(bool aSendReferrer);
+
+  uint32_t ReferrerPolicy() const;
+
+  void SetReferrerPolicy(mozilla::net::ReferrerPolicy aReferrerPolicy);
+
+  bool IsSrcdocLoad() const;
+
+  void GetSrcdocData(nsAString& aSrcdocData) const;
+
+  void SetSrcdocData(const nsAString& aSrcdocData);
+
+  nsIDocShell* SourceDocShell() const;
+
+  void SetSourceDocShell(nsIDocShell* aSourceDocShell);
+
+  nsIURI* BaseURI() const;
+
+  void SetBaseURI(nsIURI* aBaseURI);
+
+  // Helper function allowing convenient work with mozilla::Maybe in C++, hiding
+  // resultPrincipalURI and resultPrincipalURIIsSome attributes from the consumer.
+  void
+  GetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>>& aRPURI) const;
+
+  void
+  SetMaybeResultPrincipalURI(mozilla::Maybe<nsCOMPtr<nsIURI>> const& aRPURI);
 
 protected:
   virtual ~nsDocShellLoadInfo();
 
 protected:
+  // This is the referrer for the load.
   nsCOMPtr<nsIURI> mReferrer;
+
+  // The originalURI to be passed to nsIDocShell.internalLoad. May be null.
   nsCOMPtr<nsIURI> mOriginalURI;
+
+  // Result principal URL from nsILoadInfo, may be null. Valid only if
+  // mResultPrincipalURIIsSome is true (has the same meaning as isSome() on
+  // mozilla::Maybe.)
   nsCOMPtr<nsIURI> mResultPrincipalURI;
-  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   bool mResultPrincipalURIIsSome;
+
+  // The principal of the load, that is, the entity responsible for causing the
+  // load to occur. In most cases the referrer and the triggeringPrincipal's URI
+  // will be identical.
+  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+
+  // loadReplace flag to be passed to nsIDocShell.internalLoad.
   bool mLoadReplace;
+
+  // If this attribute is true and no triggeringPrincipal is specified,
+  // copy the principal from the referring document.
   bool mInheritPrincipal;
+
+  // If this attribute is true only ever use the principal specified
+  // by the triggeringPrincipal and inheritPrincipal attributes.
+  // If there are security reasons for why this is unsafe, such
+  // as trying to use a systemprincipal as the triggeringPrincipal
+  // for a content docshell the load fails.
   bool mPrincipalIsExplicit;
+
+  // If this attribute is true, then a top-level navigation
+  // to a data URI will be allowed.
   bool mForceAllowDataURI;
+
+  // If this attribute is true, this load corresponds to a frame
+  // element loading its original src (or srcdoc) attribute.
   bool mOriginalFrameSrc;
+
+  // True if the referrer should be sent, false if it shouldn't be sent, even if
+  // it's available. This attribute defaults to true.
   bool mSendReferrer;
-  nsDocShellInfoReferrerPolicy mReferrerPolicy;
-  nsDocShellInfoLoadType mLoadType;
+
+  // Referrer policy for the load. This attribute holds one of the values
+  // (REFERRER_POLICY_*) defined in nsIHttpChannel.
+  mozilla::net::ReferrerPolicy mReferrerPolicy;
+
+  // Contains a load type as specified by the nsDocShellLoadTypes::load*
+  // constants
+  uint32_t mLoadType;
+
+  // SHEntry for this page
   nsCOMPtr<nsISHEntry> mSHEntry;
+
+  // Target for load, like _content, _blank etc.
   nsString mTarget;
+
+  // Post data
   nsCOMPtr<nsIInputStream> mPostDataStream;
+
+  // Additional Headers
   nsCOMPtr<nsIInputStream> mHeadersStream;
+
+  // True if the docshell has been created to load an iframe where the srcdoc
+  // attribute has been set. Set when srcdocData is specified.
   bool mIsSrcdocLoad;
+
+  // When set, the load will be interpreted as a srcdoc load, where contents of
+  // this string will be loaded instead of the URI. Setting srcdocData sets
+  // isSrcdocLoad to true
   nsString mSrcdocData;
+
+  // When set, this is the Source Browsing Context for the navigation.
   nsCOMPtr<nsIDocShell> mSourceDocShell;
+
+  // Used for srcdoc loads to give view-source knowledge of the load's base URI
+  // as this information isn't embedded in the load's URI.
   nsCOMPtr<nsIURI> mBaseURI;
 };
 
 #endif /* nsDocShellLoadInfo_h__ */
--- a/docshell/base/nsDocShellLoadTypes.h
+++ b/docshell/base/nsDocShellLoadTypes.h
@@ -6,17 +6,17 @@
 
 #ifndef nsDocShellLoadTypes_h_
 #define nsDocShellLoadTypes_h_
 
 #ifdef MOZILLA_INTERNAL_API
 
 #include "nsDOMNavigationTiming.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 #include "nsIWebNavigation.h"
 
 /**
  * Load flag for error pages. This uses one of the reserved flag
  * values from nsIWebNavigation.
  */
 #define LOAD_FLAGS_ERROR_PAGE 0x0001U
 
@@ -34,17 +34,17 @@
                           0xffff0000)
 
 /* load types are legal combinations of load commands and flags
  *
  * NOTE:
  *  Remember to update the IsValidLoadType function below if you change this
  *  enum to ensure bad flag combinations will be rejected.
  */
-enum LoadType
+enum LoadType : uint32_t
 {
   LOAD_NORMAL = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_NONE),
   LOAD_NORMAL_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY),
   LOAD_NORMAL_EXTERNAL = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_FROM_EXTERNAL),
   LOAD_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_HISTORY, nsIWebNavigation::LOAD_FLAGS_NONE),
   LOAD_NORMAL_BYPASS_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE),
   LOAD_NORMAL_BYPASS_PROXY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
   LOAD_NORMAL_BYPASS_PROXY_AND_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
@@ -71,16 +71,28 @@ enum LoadType
    */
   LOAD_ERROR_PAGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL,
                                    LOAD_FLAGS_ERROR_PAGE)
 
   // NOTE: Adding a new value? Remember to update IsValidLoadType!
 };
 
 static inline bool
+IsForceReloadType(uint32_t aLoadType) {
+  switch (aLoadType) {
+    case LOAD_RELOAD_BYPASS_CACHE:
+    case LOAD_RELOAD_BYPASS_PROXY:
+    case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
+    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
+      return true;
+  }
+  return false;
+}
+
+static inline bool
 IsValidLoadType(uint32_t aLoadType)
 {
   switch (aLoadType) {
     case LOAD_NORMAL:
     case LOAD_NORMAL_REPLACE:
     case LOAD_NORMAL_EXTERNAL:
     case LOAD_NORMAL_BYPASS_CACHE:
     case LOAD_NORMAL_BYPASS_PROXY:
@@ -103,192 +115,16 @@ IsValidLoadType(uint32_t aLoadType)
     case LOAD_PUSHSTATE:
     case LOAD_REPLACE_BYPASS_CACHE:
     case LOAD_ERROR_PAGE:
       return true;
   }
   return false;
 }
 
-static inline bool
-IsForceReloadType(uint32_t aLoadType) {
-  switch (aLoadType) {
-    case LOAD_RELOAD_BYPASS_CACHE:
-    case LOAD_RELOAD_BYPASS_PROXY:
-    case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
-    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
-      return true;
-  }
-  return false;
-}
-
-static inline nsDocShellInfoLoadType
-ConvertLoadTypeToDocShellInfoLoadType(uint32_t aLoadType)
-{
-  nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
-  switch (aLoadType) {
-    case LOAD_NORMAL:
-      docShellLoadType = nsIDocShellLoadInfo::loadNormal;
-      break;
-    case LOAD_NORMAL_REPLACE:
-      docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
-      break;
-    case LOAD_NORMAL_EXTERNAL:
-      docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
-      break;
-    case LOAD_NORMAL_BYPASS_CACHE:
-      docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache;
-      break;
-    case LOAD_NORMAL_BYPASS_PROXY:
-      docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy;
-      break;
-    case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
-      docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache;
-      break;
-    case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
-      docShellLoadType = nsIDocShellLoadInfo::loadNormalAllowMixedContent;
-      break;
-    case LOAD_HISTORY:
-      docShellLoadType = nsIDocShellLoadInfo::loadHistory;
-      break;
-    case LOAD_RELOAD_NORMAL:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
-      break;
-    case LOAD_RELOAD_CHARSET_CHANGE:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
-      break;
-    case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChangeBypassCache;
-      break;
-    case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChangeBypassProxyAndCache;
-      break;
-    case LOAD_RELOAD_BYPASS_CACHE:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
-      break;
-    case LOAD_RELOAD_BYPASS_PROXY:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
-      break;
-    case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
-      break;
-    case LOAD_LINK:
-      docShellLoadType = nsIDocShellLoadInfo::loadLink;
-      break;
-    case LOAD_REFRESH:
-      docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
-      break;
-    case LOAD_BYPASS_HISTORY:
-    case LOAD_ERROR_PAGE:
-      docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
-      break;
-    case LOAD_STOP_CONTENT:
-      docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
-      break;
-    case LOAD_STOP_CONTENT_AND_REPLACE:
-      docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
-      break;
-    case LOAD_PUSHSTATE:
-      docShellLoadType = nsIDocShellLoadInfo::loadPushState;
-      break;
-    case LOAD_REPLACE_BYPASS_CACHE:
-      docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache;
-      break;
-    case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
-      docShellLoadType = nsIDocShellLoadInfo::loadReloadMixedContent;
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("Unexpected load type value");
-  }
-
-  return docShellLoadType;
-}
-
-static inline uint32_t
-ConvertDocShellInfoLoadTypeToLoadType(nsDocShellInfoLoadType aDocShellLoadType)
-{
-  uint32_t loadType = LOAD_NORMAL;
-
-  switch (aDocShellLoadType) {
-    case nsIDocShellLoadInfo::loadNormal:
-      loadType = LOAD_NORMAL;
-      break;
-    case nsIDocShellLoadInfo::loadNormalReplace:
-      loadType = LOAD_NORMAL_REPLACE;
-      break;
-    case nsIDocShellLoadInfo::loadNormalExternal:
-      loadType = LOAD_NORMAL_EXTERNAL;
-      break;
-    case nsIDocShellLoadInfo::loadHistory:
-      loadType = LOAD_HISTORY;
-      break;
-    case nsIDocShellLoadInfo::loadNormalBypassCache:
-      loadType = LOAD_NORMAL_BYPASS_CACHE;
-      break;
-    case nsIDocShellLoadInfo::loadNormalBypassProxy:
-      loadType = LOAD_NORMAL_BYPASS_PROXY;
-      break;
-    case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache:
-      loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE;
-      break;
-    case nsIDocShellLoadInfo::loadNormalAllowMixedContent:
-      loadType = LOAD_NORMAL_ALLOW_MIXED_CONTENT;
-      break;
-    case nsIDocShellLoadInfo::loadReloadNormal:
-      loadType = LOAD_RELOAD_NORMAL;
-      break;
-    case nsIDocShellLoadInfo::loadReloadCharsetChange:
-      loadType = LOAD_RELOAD_CHARSET_CHANGE;
-      break;
-    case nsIDocShellLoadInfo::loadReloadCharsetChangeBypassCache:
-      loadType = LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE;
-      break;
-    case nsIDocShellLoadInfo::loadReloadCharsetChangeBypassProxyAndCache:
-      loadType = LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE;
-      break;
-    case nsIDocShellLoadInfo::loadReloadBypassCache:
-      loadType = LOAD_RELOAD_BYPASS_CACHE;
-      break;
-    case nsIDocShellLoadInfo::loadReloadBypassProxy:
-      loadType = LOAD_RELOAD_BYPASS_PROXY;
-      break;
-    case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
-      loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
-      break;
-    case nsIDocShellLoadInfo::loadLink:
-      loadType = LOAD_LINK;
-      break;
-    case nsIDocShellLoadInfo::loadRefresh:
-      loadType = LOAD_REFRESH;
-      break;
-    case nsIDocShellLoadInfo::loadBypassHistory:
-      loadType = LOAD_BYPASS_HISTORY;
-      break;
-    case nsIDocShellLoadInfo::loadStopContent:
-      loadType = LOAD_STOP_CONTENT;
-      break;
-    case nsIDocShellLoadInfo::loadStopContentAndReplace:
-      loadType = LOAD_STOP_CONTENT_AND_REPLACE;
-      break;
-    case nsIDocShellLoadInfo::loadPushState:
-      loadType = LOAD_PUSHSTATE;
-      break;
-    case nsIDocShellLoadInfo::loadReplaceBypassCache:
-      loadType = LOAD_REPLACE_BYPASS_CACHE;
-      break;
-    case nsIDocShellLoadInfo::loadReloadMixedContent:
-      loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("Unexpected nsDocShellInfoLoadType value");
-  }
-
-  return loadType;
-}
-
 static inline nsDOMNavigationTiming::Type
 ConvertLoadTypeToNavigationType(uint32_t aLoadType)
 {
   // Not initialized, assume it's normal load.
   if (aLoadType == 0) {
     aLoadType = LOAD_NORMAL;
   }
 
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -12,16 +12,17 @@
 #include "js/TypeDecls.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 class nsPresContext;
 class nsIPresShell;
+class nsDocShellLoadInfo;
 namespace mozilla {
 class Encoding;
 class HTMLEditor;
 namespace dom {
 class ClientSource;
 } // namespace dom
 }
 %}
@@ -56,16 +57,17 @@ interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
 interface nsITabChild;
 interface nsICommandManager;
 interface nsICommandParams;
 interface nsILoadURIDelegate;
 native TabChildRef(already_AddRefed<nsITabChild>);
+native nsDocShellLoadInfoPtr(nsDocShellLoadInfo*);
 
 webidl EventTarget;
 
 [scriptable, builtinclass, uuid(049234fe-da10-478b-bc5d-bc6f9a1ba63d)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
@@ -82,17 +84,17 @@ interface nsIDocShell : nsIDocShellTreeI
    *                     then pass it to loadURI.
    * @param aLoadFlags - Flags to modify load behaviour. Flags are defined in
    *                     nsIWebNavigation.  Note that using flags outside
    *                     LOAD_FLAGS_MASK is only allowed if passing in a
    *                     non-null loadInfo.  And even some of those might not
    *                     be allowed.  Use at your own risk.
    */
   [noscript]void loadURI(in nsIURI uri,
-                         in nsIDocShellLoadInfo loadInfo,
+                         in nsDocShellLoadInfoPtr loadInfo,
                          in unsigned long aLoadFlags,
                          in boolean firstParty);
 
   const long INTERNAL_LOAD_FLAGS_NONE                    = 0x0;
   const long INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL       = 0x1;
   const long INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER      = 0x2;
   const long INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP = 0x4;
 
@@ -202,22 +204,16 @@ interface nsIDocShell : nsIDocShellTreeI
    * Do either a history.pushState() or history.replaceState() operation,
    * depending on the value of aReplace.
    */
   [implicit_jscontext]
   void addState(in jsval aData, in DOMString aTitle,
                 in DOMString aURL, in boolean aReplace);
 
   /**
-   * Creates a DocShellLoadInfo object that you can manipulate and then pass
-   * to loadURI.
-   */
-  void createLoadInfo(out nsIDocShellLoadInfo loadInfo);
-
-  /**
    * Reset state to a new content model within the current document and the document
    * viewer.  Called by the document before initiating an out of band document.write().
    */
   void prepareForNewContentModel();
 
   /**
    * For editors and suchlike who wish to change the URI associated with the
    * document. Note if you want to get the current URI, use the read-only
deleted file mode 100644
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ /dev/null
@@ -1,168 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; 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/. */
-
-#include "nsISupports.idl"
-
-/**
- * The nsIDocShellLoadInfo interface defines an interface for specifying
- * setup information used in a nsIDocShell::loadURI call.
- */
- 
-interface nsIURI;
-interface nsIInputStream;
-interface nsISHEntry;
-interface nsIDocShell;
-interface nsIPrincipal;
-
-typedef long nsDocShellInfoLoadType;
-typedef unsigned long nsDocShellInfoReferrerPolicy;
-
-[scriptable, uuid(e7570e5a-f1d6-452d-b4f8-b35fdc63aa03)]
-interface nsIDocShellLoadInfo : nsISupports
-{
-    /** This is the referrer for the load. */
-    attribute nsIURI referrer;
-
-    /**
-     * The originalURI to be passed to nsIDocShell.internalLoad. May be null.
-     */
-    attribute nsIURI originalURI;
-
-    /**
-     * Result principal URL from nsILoadInfo, may be null.  Valid only if
-     * the "IsSome" part is true (has the same meaning as isSome()
-     * on mozilla::Maybe.)
-     *
-     * In C++ please use Get/SetMaybeResultPrincipalURI helper functions.
-     */
-    attribute nsIURI resultPrincipalURI;
-    attribute boolean resultPrincipalURIIsSome;
-
-    /**
-     * loadReplace flag to be passed to nsIDocShell.internalLoad.
-     */
-    attribute boolean loadReplace;
-
-    /** The principal of the load, that is, the entity responsible for 
-     *  causing the load to occur. In most cases the referrer and
-     *  the triggeringPrincipal's URI will be identical.
-     */
-    attribute nsIPrincipal triggeringPrincipal;
-
-    /** If this attribute is true and no triggeringPrincipal is specified,
-     * copy the principal from the referring document.
-     */
-    attribute boolean inheritPrincipal;
-
-    /** If this attribute is true only ever use the principal specified
-     *  by the triggeringPrincipal and inheritPrincipal attributes.
-     *  If there are security reasons for why this is unsafe, such
-     *  as trying to use a systemprincipal as the triggeringPrincipal
-     *  for a content docshell the load fails.
-     */
-    attribute boolean principalIsExplicit;
-
-    /**
-     * If this attribute is true, then a top-level navigation
-     * to a data URI will be allowed.
-     */
-    attribute boolean forceAllowDataURI;
-
-    /**
-     * If this attribute is true, this load corresponds to a frame
-     * element loading its original src (or srcdoc) attribute.
-     */
-    attribute boolean originalFrameSrc;
-
-    /* these are load type enums... */
-    const long loadNormal = 0;                     // Normal Load
-    const long loadNormalReplace = 1;              // Normal Load but replaces current history slot
-    const long loadHistory = 2;                    // Load from history
-    const long loadReloadNormal = 3;               // Reload
-    const long loadReloadBypassCache = 4;
-    const long loadReloadBypassProxy = 5;
-    const long loadReloadBypassProxyAndCache = 6;
-    const long loadLink = 7;
-    const long loadRefresh = 8;
-    const long loadReloadCharsetChange = 9;
-    const long loadBypassHistory = 10;
-    const long loadStopContent = 11;
-    const long loadStopContentAndReplace = 12;
-    const long loadNormalExternal = 13;
-    const long loadNormalBypassCache = 14;
-    const long loadNormalBypassProxy = 15;
-    const long loadNormalBypassProxyAndCache = 16;
-    const long loadPushState = 17;                 // history.pushState or replaceState
-    const long loadReplaceBypassCache = 18;
-    const long loadReloadMixedContent = 19;
-    const long loadNormalAllowMixedContent = 20;
-    const long loadReloadCharsetChangeBypassCache = 21;
-    const long loadReloadCharsetChangeBypassProxyAndCache = 22;
-
-    /** Contains a load type as specified by the load* constants */
-    attribute nsDocShellInfoLoadType loadType;
-
-    /** SHEntry for this page */
-    attribute nsISHEntry SHEntry;
-
-    /** Target for load, like _content, _blank etc. */
-    attribute wstring target;
-
-    /** Post data */
-    attribute nsIInputStream postDataStream;
-
-    /** Additional headers */
-    attribute nsIInputStream headersStream;
-
-    /** True if the referrer should be sent, false if it shouldn't be
-     *  sent, even if it's available. This attribute defaults to true.
-     */
-    attribute boolean sendReferrer;
-
-    /** Referrer policy for the load. This attribute holds one of
-     *  the values (REFERRER_POLICY_*) defined in nsIHttpChannel.
-     */
-    attribute nsDocShellInfoReferrerPolicy referrerPolicy;
-
-    /** True if the docshell has been created to load an iframe where the
-     * srcdoc attribute has been set.  Set when srcdocData is specified.
-     */
-    readonly attribute boolean isSrcdocLoad;
-
-    /** When set, the load will be interpreted as a srcdoc load, where contents
-     * of this string will be loaded instead of the URI.  Setting srcdocData
-     * sets isSrcdocLoad to true
-     */
-    attribute AString srcdocData;
-
-    /** When set, this is the Source Browsing Context for the navigation. */
-    attribute nsIDocShell sourceDocShell;
-
-    /**
-     * Used for srcdoc loads to give view-source knowledge of the load's base
-     * URI as this information isn't embedded in the load's URI.
-     */
-    attribute nsIURI baseURI;
-};
-
-%{C++
-
-#include "mozilla/Maybe.h"
-
-namespace mozilla {
-
-/**
- * Helper function allowing convenient work with mozilla::Maybe in C++, hiding
- * resultPrincipalURI and resultPrincipalURIIsSome attributes from the consumer.
- */
-void
-GetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>>& aRPURI);
-void
-SetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>> const& aRPURI);
-
-} // mozilla
-
-%}
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -341,16 +341,27 @@ interface nsISHEntry : nsISupports
     readonly attribute boolean loadedInThisProcess;
 
     /**
      * The session history it belongs to. It's usually only set on root entries.
      * SHEntry is strictly bound to the SHistory it belongs to; it should not be
      * changed once set to a non-null value.
      */
     [noscript] attribute nsISHistory SHistory;
+
+    /**
+     * Sets an SHEntry to reflect that it is a history type load. as
+     * nsIDocShellLoadInfo and its LoadType enum were removed, this is the
+     * equivalent to doing
+     *
+     * shEntry.loadType = 4;
+     *
+     * in js, but easier to maintain and less opaque.
+     */
+    void setAsHistoryLoad();
 };
 
 [scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)]
 interface nsISHEntryInternal : nsISupports
 {
     [notxpcom] void RemoveFromBFCacheAsync();
     [notxpcom] void RemoveFromBFCacheSync();
 
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSHEntry.h"
 
 #include <algorithm>
 
 #include "nsDocShellEditorData.h"
 #include "nsIContentViewer.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIInputStream.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIStructuredCloneContainer.h"
 #include "nsIURI.h"
 #include "nsSHEntryShared.h"
 #include "nsSHistory.h"
 
@@ -448,17 +448,17 @@ nsSHEntry::Create(nsIURI* aURI, const ns
   MOZ_ASSERT(aTriggeringPrincipal,
              "need a valid triggeringPrincipal to create a session history entry");
 
   mURI = aURI;
   mTitle = aTitle;
   mPostData = aInputStream;
 
   // Set the LoadType by default to loadHistory during creation
-  mLoadType = (uint32_t)nsIDocShellLoadInfo::loadHistory;
+  mLoadType = LOAD_HISTORY;
 
   mShared->mCacheKey = aCacheKey;
   mShared->mContentType = aContentType;
   mShared->mTriggeringPrincipal = aTriggeringPrincipal;
   mShared->mPrincipalToInherit = aPrincipalToInherit;
   mShared->mDocShellID = aDocShellID;
   mShared->mDynamicallyCreated = aDynamicCreation;
 
@@ -1006,8 +1006,16 @@ NS_IMETHODIMP
 nsSHEntry::SetSHistory(nsISHistory* aSHistory)
 {
   nsWeakPtr shistory = do_GetWeakReference(aSHistory);
   // mSHistory can not be changed once it's set
   MOZ_ASSERT(!mShared->mSHistory || (mShared->mSHistory == shistory));
   mShared->mSHistory = shistory;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsSHEntry::SetAsHistoryLoad()
+{
+  // Set the LoadType by default to loadHistory during creation
+  mLoadType = LOAD_HISTORY;
+  return NS_OK;
+}
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -8,17 +8,17 @@
 
 #include <algorithm>
 
 #include "nsCOMArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDocShell.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIObserverService.h"
 #include "nsISHContainer.h"
 #include "nsISHEntry.h"
 #include "nsISHistoryListener.h"
 #include "nsISHTransaction.h"
 #include "nsIURI.h"
@@ -1109,49 +1109,49 @@ NS_IMETHODIMP
 nsSHistory::GoBack()
 {
   bool canGoBack = false;
 
   GetCanGoBack(&canGoBack);
   if (!canGoBack) {
     return NS_ERROR_UNEXPECTED;
   }
-  return LoadEntry(mIndex - 1, nsIDocShellLoadInfo::loadHistory, HIST_CMD_BACK);
+  return LoadEntry(mIndex - 1, LOAD_HISTORY, HIST_CMD_BACK);
 }
 
 NS_IMETHODIMP
 nsSHistory::GoForward()
 {
   bool canGoForward = false;
 
   GetCanGoForward(&canGoForward);
   if (!canGoForward) {
     return NS_ERROR_UNEXPECTED;
   }
-  return LoadEntry(mIndex + 1, nsIDocShellLoadInfo::loadHistory,
+  return LoadEntry(mIndex + 1, LOAD_HISTORY,
                    HIST_CMD_FORWARD);
 }
 
 NS_IMETHODIMP
 nsSHistory::Reload(uint32_t aReloadFlags)
 {
-  nsDocShellInfoLoadType loadType;
+  uint32_t loadType;
   if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY &&
       aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) {
-    loadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
+    loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
   } else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY) {
-    loadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
+    loadType = LOAD_RELOAD_BYPASS_PROXY;
   } else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) {
-    loadType = nsIDocShellLoadInfo::loadReloadBypassCache;
+    loadType = LOAD_RELOAD_BYPASS_CACHE;
   } else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE) {
-    loadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
+    loadType = LOAD_RELOAD_CHARSET_CHANGE;
   } else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
-    loadType = nsIDocShellLoadInfo::loadReloadMixedContent;
+    loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
   } else {
-    loadType = nsIDocShellLoadInfo::loadReloadNormal;
+    loadType = LOAD_RELOAD_NORMAL;
   }
 
   // We are reloading. Send Reload notifications.
   // nsDocShellLoadFlagType is not public, where as nsIWebNavigation
   // is public. So send the reload notifications with the
   // nsIWebNavigation flags.
   bool canNavigate = true;
   nsCOMPtr<nsIURI> currentURI;
@@ -1173,33 +1173,33 @@ nsSHistory::ReloadCurrentEntry()
   nsCOMPtr<nsIURI> currentURI;
   GetCurrentURI(getter_AddRefs(currentURI));
   NOTIFY_LISTENERS_CANCELABLE(OnHistoryGotoIndex, canNavigate,
                               (mIndex, currentURI, &canNavigate));
   if (!canNavigate) {
     return NS_OK;
   }
 
-  return LoadEntry(mIndex, nsIDocShellLoadInfo::loadHistory, HIST_CMD_RELOAD);
+  return LoadEntry(mIndex, LOAD_HISTORY, HIST_CMD_RELOAD);
 }
 
 NS_IMETHODIMP
 nsSHistory::RestoreToEntryAtIndex(int32_t aIndex)
 {
   mRequestedIndex = aIndex;
 
   nsCOMPtr<nsISHEntry> nextEntry;
   GetEntryAtIndex(mRequestedIndex, false, getter_AddRefs(nextEntry));
   if (!nextEntry) {
     mRequestedIndex = -1;
     return NS_ERROR_FAILURE;
   }
 
   // XXX We may want to ensure docshell is currently holding about:blank
-  return InitiateLoad(nextEntry, mRootDocShell, nsIDocShellLoadInfo::loadHistory);
+  return InitiateLoad(nextEntry, mRootDocShell, LOAD_HISTORY);
 }
 
 void
 nsSHistory::EvictOutOfRangeWindowContentViewers(int32_t aIndex)
 {
   // XXX rename method to EvictContentViewersExceptAroundIndex, or something.
 
   // We need to release all content viewers that are no longer in the range
@@ -1835,17 +1835,17 @@ nsSHistory::LoadURI(const char16_t* aURI
                     nsIPrincipal* aTriggeringPrincipal)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHistory::GotoIndex(int32_t aIndex)
 {
-  return LoadEntry(aIndex, nsIDocShellLoadInfo::loadHistory, HIST_CMD_GOTOINDEX);
+  return LoadEntry(aIndex, LOAD_HISTORY, HIST_CMD_GOTOINDEX);
 }
 
 nsresult
 nsSHistory::LoadNextPossibleEntry(int32_t aNewIndex, long aLoadType,
                                   uint32_t aHistCmd)
 {
   mRequestedIndex = -1;
   if (aNewIndex < mIndex) {
@@ -2034,24 +2034,23 @@ nsSHistory::LoadDifferingEntries(nsISHEn
 }
 
 nsresult
 nsSHistory::InitiateLoad(nsISHEntry* aFrameEntry, nsIDocShell* aFrameDS,
                          long aLoadType)
 {
   NS_ENSURE_STATE(aFrameDS && aFrameEntry);
 
-  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
+  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
 
   /* Set the loadType in the SHEntry too to  what was passed on.
    * This will be passed on to child subframes later in nsDocShell,
    * so that proper loadType is maintained through out a frameset
    */
   aFrameEntry->SetLoadType(aLoadType);
-  aFrameDS->CreateLoadInfo(getter_AddRefs(loadInfo));
 
   loadInfo->SetLoadType(aLoadType);
   loadInfo->SetSHEntry(aFrameEntry);
 
   nsCOMPtr<nsIURI> originalURI;
   aFrameEntry->GetOriginalURI(getter_AddRefs(originalURI));
   loadInfo->SetOriginalURI(originalURI);
 
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -441,16 +441,17 @@ public:
   ParentRunnable(const PrincipalInfo& aPrincipalInfo,
                  OpenMode aOpenMode,
                  const WriteParams& aWriteParams)
   : mOwningEventTarget(GetCurrentThreadEventTarget()),
     mPrincipalInfo(aPrincipalInfo),
     mOpenMode(aOpenMode),
     mWriteParams(aWriteParams),
     mOperationMayProceed(true),
+    mModuleIndex(0),
     mState(eInitial),
     mResult(JS::AsmJSCache_InternalError),
     mActorDestroyed(false),
     mOpened(false)
   {
     MOZ_ASSERT(XRE_IsParentProcess());
     AssertIsOnOwningThread();
   }
--- a/dom/base/DOMException.h
+++ b/dom/base/DOMException.h
@@ -130,17 +130,16 @@ protected:
     }
   }
 
   nsCString       mMessage;
   nsresult        mResult;
   nsCString       mName;
   nsCOMPtr<nsIStackFrame> mLocation;
   nsCOMPtr<nsISupports> mData;
-  bool            mInitialized;
 
   bool mHoldingJSVal;
   JS::Heap<JS::Value> mThrownJSVal;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(Exception, MOZILLA_EXCEPTION_IID)
 
 class DOMException : public Exception
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -191,17 +191,17 @@ DOMRequest::Then(JSContext* aCx, AnyCall
       } else {
         mPromise->MaybeResolve(mResult);
       }
     }
   }
 
   // Just use the global of the Promise itself as the callee global.
   JS::Rooted<JSObject*> global(aCx, mPromise->PromiseObj());
-  global = js::GetGlobalForObjectCrossCompartment(global);
+  global = JS::GetNonCCWObjectGlobal(global);
   mPromise->Then(aCx, global, aResolveCallback, aRejectCallback, aRetval, aRv);
 }
 
 NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService)
 
 NS_IMETHODIMP
 DOMRequestService::CreateRequest(mozIDOMWindow* aWindow,
                                  DOMRequest** aRequest)
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1876,25 +1876,42 @@ RemoveFromBindingManagerRunnable::Run()
   if (!mContent->IsInComposedDoc()) {
     mManager->RemovedFromDocumentInternal(mContent, mDoc,
                                           nsBindingManager::eRunDtor);
   }
 
   return NS_OK;
 }
 
+static bool
+ShouldRemoveFromIdTableOnUnbind(const Element& aElement, bool aNullParent)
+{
+  if (aElement.IsInUncomposedDoc()) {
+    return true;
+  }
+
+  if (!aElement.IsInShadowTree()) {
+    return false;
+  }
+
+  return aNullParent || !aElement.GetParent()->IsInShadowTree();
+}
 
 void
 Element::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   MOZ_ASSERT(aDeep || (!GetUncomposedDoc() && !GetBindingParent()),
                   "Shallow unbind won't clear document and binding parent on "
                   "kids!");
 
-  RemoveFromIdTable();
+  // Make sure to only remove from the ID table if our subtree root is actually
+  // changing.
+  if (ShouldRemoveFromIdTableOnUnbind(*this, aNullParent)) {
+    RemoveFromIdTable();
+  }
 
   // Make sure to unbind this node before doing the kids
   nsIDocument* document = GetComposedDoc();
 
   if (HasPointerLock()) {
     nsIDocument::UnlockPointer();
   }
   if (mState.HasState(NS_EVENT_STATE_FULL_SCREEN)) {
@@ -1926,17 +1943,17 @@ Element::UnbindFromTree(bool aDeep, bool
         nsIContent* parent = GetParent();
         while (parent) {
           parent->ChangeEditableDescendantCount(editableDescendantChange);
           parent = parent->GetParent();
         }
       }
     }
 
-    if (this->IsRootOfNativeAnonymousSubtree()) {
+    if (IsRootOfNativeAnonymousSubtree()) {
       nsNodeUtils::NativeAnonymousChildListChange(this, true);
     }
 
     if (GetParent()) {
       RefPtr<nsINode> p;
       p.swap(mParent);
     } else {
       mParent = nullptr;
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -450,16 +450,17 @@ class InitRunnable final : public Worker
 public:
   InitRunnable(WorkerPrivate* aWorkerPrivate,
                EventSourceImpl* aEventSourceImpl,
                const nsAString& aURL)
     : WorkerMainThreadRunnable(aWorkerPrivate,
                                NS_LITERAL_CSTRING("EventSource :: Init"))
     , mImpl(aEventSourceImpl)
     , mURL(aURL)
+    , mRv(NS_ERROR_NOT_INITIALIZED)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   bool MainThreadRun() override
   {
     // Get principal from worker's owner document or from worker.
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -758,20 +758,22 @@ FragmentOrElement::nsExtendedDOMSlots::~
 
 void
 FragmentOrElement::nsExtendedDOMSlots::UnlinkExtendedSlots()
 {
   nsIContent::nsExtendedContentSlots::UnlinkExtendedSlots();
 
   // Don't clear mXBLBinding, it'll be done in
   // BindingManager::RemovedFromDocument from FragmentOrElement::Unlink.
+  //
+  // mShadowRoot will similarly be cleared explicitly from
+  // FragmentOrElement::Unlink.
   mSMILOverrideStyle = nullptr;
   mControllers = nullptr;
   mLabelsList = nullptr;
-  mShadowRoot = nullptr;
   if (mCustomElementData) {
     mCustomElementData->Unlink();
     mCustomElementData = nullptr;
   }
 }
 
 void
 FragmentOrElement::nsExtendedDOMSlots::TraverseExtendedSlots(nsCycleCollectionTraversalCallback& aCb)
@@ -1495,16 +1497,27 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Fr
     The subtree root will end up to a ContentUnbinder, and that will
     unbind the child nodes.
   } */
 
   // Clear flag here because unlinking slots will clear the
   // containing shadow root pointer.
   tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
+  if (ShadowRoot* shadowRoot = tmp->GetShadowRoot()) {
+    for (nsIContent* child = shadowRoot->GetFirstChild();
+         child;
+         child = child->GetNextSibling()) {
+      child->UnbindFromTree(true, false);
+    }
+
+    shadowRoot->SetIsComposedDocParticipant(false);
+    tmp->ExtendedDOMSlots()->mShadowRoot = nullptr;
+  }
+
   nsIDocument* doc = tmp->OwnerDoc();
   doc->BindingManager()->RemovedFromDocument(tmp, doc,
                                              nsBindingManager::eDoNotRunDtor);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(FragmentOrElement)
 
 void
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Location.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 #include "nsIWebNavigation.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIURIFixup.h"
 #include "nsIURL.h"
 #include "nsIURIMutator.h"
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #include "nsCOMPtr.h"
@@ -57,17 +57,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Location, mInnerWindow)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Location)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Location)
 
 nsresult
-Location::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
+Location::CheckURL(nsIURI* aURI, nsDocShellLoadInfo** aLoadInfo)
 {
   *aLoadInfo = nullptr;
 
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   NS_ENSURE_TRUE(docShell, NS_ERROR_NOT_AVAILABLE);
 
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   nsCOMPtr<nsIURI> sourceURI;
@@ -145,19 +145,17 @@ Location::CheckURL(nsIURI* aURI, nsIDocS
       // subjectPrincipal, wich is the principal of the current JS
       // compartment, or a null principal in case there is no
       // compartment yet.
       triggeringPrincipal = nsContentUtils::SubjectPrincipal();
     }
   }
 
   // Create load info
-  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
-  docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
-  NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
+  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
 
   loadInfo->SetTriggeringPrincipal(triggeringPrincipal);
 
   if (sourceURI) {
     loadInfo->SetReferrer(sourceURI);
     loadInfo->SetReferrerPolicy(referrerPolicy);
   }
 
@@ -228,25 +226,25 @@ Location::GetWritableURI(nsIURI** aURI, 
   return uri->CloneWithNewRef(*aNewRef, aURI);
 }
 
 nsresult
 Location::SetURI(nsIURI* aURI, bool aReplace)
 {
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   if (docShell) {
-    nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
+    RefPtr<nsDocShellLoadInfo> loadInfo;
 
     if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
       return NS_ERROR_FAILURE;
 
     if (aReplace) {
-      loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace);
+      loadInfo->SetLoadType(LOAD_STOP_CONTENT_AND_REPLACE);
     } else {
-      loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
+      loadInfo->SetLoadType(LOAD_STOP_CONTENT);
     }
 
     // Get the incumbent script's browsing context to set as source.
     nsCOMPtr<nsPIDOMWindowInner> sourceWindow =
       do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
     if (sourceWindow) {
       loadInfo->SetSourceDocShell(sourceWindow->GetDocShell());
     }
--- a/dom/base/Location.h
+++ b/dom/base/Location.h
@@ -11,17 +11,16 @@
 #include "mozilla/ErrorResult.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 
 class nsIDocShell;
-class nsIDocShellLoadInfo;
 class nsIURI;
 
 namespace mozilla {
 namespace dom {
 
 //*****************************************************************************
 // Location: Script "location" object
 //*****************************************************************************
@@ -174,17 +173,17 @@ protected:
                           const nsACString* aNewRef = nullptr);
   nsresult SetURI(nsIURI* aURL, bool aReplace = false);
   nsresult SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
                            bool aReplace);
   nsresult SetHrefWithContext(JSContext* cx, const nsAString& aHref,
                               bool aReplace);
 
   nsresult GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL);
-  nsresult CheckURL(nsIURI *url, nsIDocShellLoadInfo** aLoadInfo);
+  nsresult CheckURL(nsIURI *url, nsDocShellLoadInfo** aLoadInfo);
   bool CallerSubsumes(nsIPrincipal* aSubjectPrincipal);
 
   nsString mCachedHash;
   nsCOMPtr<nsPIDOMWindowInner> mInnerWindow;
   nsWeakPtr mDocShell;
 };
 
 } // dom namespace
--- a/dom/base/NodeIterator.h
+++ b/dom/base/NodeIterator.h
@@ -66,17 +66,21 @@ public:
     void Detach();
 
     bool WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector);
 
 private:
     virtual ~NodeIterator();
 
     struct NodePointer {
-        NodePointer() : mNode(nullptr) {}
+        NodePointer()
+          : mNode(nullptr)
+          , mBeforeNode(false)
+        {
+        }
         NodePointer(nsINode *aNode, bool aBeforeNode);
 
         typedef bool (NodePointer::*MoveToMethodType)(nsINode*);
         bool MoveToNext(nsINode *aRoot);
         bool MoveToPrevious(nsINode *aRoot);
 
         bool MoveForward(nsINode *aRoot, nsINode *aNode);
         void MoveBackward(nsINode *aParent, nsINode *aNode);
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -34,16 +34,17 @@ class TextInputProcessorNotification fin
   typedef IMENotification::SelectionChangeData SelectionChangeData;
   typedef IMENotification::SelectionChangeDataBase SelectionChangeDataBase;
   typedef IMENotification::TextChangeData TextChangeData;
   typedef IMENotification::TextChangeDataBase TextChangeDataBase;
 
 public:
   explicit TextInputProcessorNotification(const char* aType)
     : mType(aType)
+    , mTextChangeData()
   {
   }
 
   explicit TextInputProcessorNotification(
              const TextChangeDataBase& aTextChangeData)
     : mType("notify-text-change")
     , mTextChangeData(aTextChangeData)
   {
@@ -274,17 +275,20 @@ protected:
 private:
   nsAutoCString mType;
   union
   {
     TextChangeDataBase mTextChangeData;
     SelectionChangeDataBase mSelectionChangeData;
   };
 
-  TextInputProcessorNotification() { }
+  TextInputProcessorNotification()
+    : mTextChangeData()
+  {
+  }
 };
 
 NS_IMPL_ISUPPORTS(TextInputProcessorNotification,
                   nsITextInputProcessorNotification)
 
 /******************************************************************************
  * TextInputProcessor
  ******************************************************************************/
--- a/dom/base/nsContentList.h
+++ b/dom/base/nsContentList.h
@@ -570,31 +570,35 @@ class nsCacheableFuncStringContentList :
 public:
   virtual ~nsCacheableFuncStringContentList();
 
   bool Equals(const nsFuncStringCacheKey* aKey) {
     return mRootNode == aKey->mRootNode && mFunc == aKey->mFunc &&
       mString == aKey->mString;
   }
 
-#ifdef DEBUG
   enum ContentListType {
     eNodeList,
     eHTMLCollection
   };
+#ifdef DEBUG
   ContentListType mType;
 #endif
 
 protected:
   nsCacheableFuncStringContentList(nsINode* aRootNode,
                                    nsContentListMatchFunc aFunc,
                                    nsContentListDestroyFunc aDestroyFunc,
                                    nsFuncStringContentListDataAllocator aDataAllocator,
-                                   const nsAString& aString) :
+                                   const nsAString& aString,
+                                   mozilla::DebugOnly<ContentListType> aType) :
     nsContentList(aRootNode, aFunc, aDestroyFunc, nullptr),
+#ifdef DEBUG
+    mType(aType),
+#endif
     mString(aString)
   {
     mData = (*aDataAllocator)(aRootNode, &mString);
     MOZ_ASSERT(mData);
   }
 
   virtual void RemoveFromCaches() override {
     RemoveFromFuncStringHashtable();
@@ -609,21 +613,18 @@ class nsCachableElementsByNameNodeList
 {
 public:
   nsCachableElementsByNameNodeList(nsINode* aRootNode,
                                    nsContentListMatchFunc aFunc,
                                    nsContentListDestroyFunc aDestroyFunc,
                                    nsFuncStringContentListDataAllocator aDataAllocator,
                                    const nsAString& aString)
     : nsCacheableFuncStringContentList(aRootNode, aFunc, aDestroyFunc,
-                                       aDataAllocator, aString)
+                                       aDataAllocator, aString, eNodeList)
   {
-#ifdef DEBUG
-    mType = eNodeList;
-#endif
   }
 
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
 
   virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 #ifdef DEBUG
   static const ContentListType sType;
@@ -635,21 +636,18 @@ class nsCacheableFuncStringHTMLCollectio
 {
 public:
   nsCacheableFuncStringHTMLCollection(nsINode* aRootNode,
                                       nsContentListMatchFunc aFunc,
                                       nsContentListDestroyFunc aDestroyFunc,
                                       nsFuncStringContentListDataAllocator aDataAllocator,
                                       const nsAString& aString)
     : nsCacheableFuncStringContentList(aRootNode, aFunc, aDestroyFunc,
-                                       aDataAllocator, aString)
+                                       aDataAllocator, aString, eHTMLCollection)
   {
-#ifdef DEBUG
-    mType = eHTMLCollection;
-#endif
   }
 
   virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 #ifdef DEBUG
   static const ContentListType sType;
 #endif
 };
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -162,18 +162,18 @@ ContentPermissionRequestParent::ContentP
 ContentPermissionRequestParent::~ContentPermissionRequestParent()
 {
   MOZ_COUNT_DTOR(ContentPermissionRequestParent);
 }
 
 mozilla::ipc::IPCResult
 ContentPermissionRequestParent::Recvprompt()
 {
-  mProxy = new nsContentPermissionRequestProxy();
-  if (NS_FAILED(mProxy->Init(mRequests, this))) {
+  mProxy = new nsContentPermissionRequestProxy(this);
+  if (NS_FAILED(mProxy->Init(mRequests))) {
     mProxy->Cancel();
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentPermissionRequestParent::RecvNotifyVisibility(const bool& aIsVisible)
 {
@@ -573,30 +573,29 @@ nsContentPermissionRequestProxy::nsConte
     return;
   }
 
   if (mOnChangeCallback) {
     mOnChangeCallback->NotifyVisibility(aIsVisible);
   }
 }
 
-nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
+nsContentPermissionRequestProxy::nsContentPermissionRequestProxy(ContentPermissionRequestParent* parent)
+  : mParent(parent)
 {
+    NS_ASSERTION(mParent, "null parent");
 }
 
 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
 {
 }
 
 nsresult
-nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
-                                      ContentPermissionRequestParent* parent)
+nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests)
 {
-  NS_ASSERTION(parent, "null parent");
-  mParent = parent;
   mPermissionRequests = requests;
   mRequester = new nsContentPermissionRequesterProxy(mParent);
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   if (!prompt) {
     return NS_ERROR_FAILURE;
   }
 
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -121,20 +121,19 @@ private:
 using mozilla::dom::ContentPermissionRequestParent;
 
 class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUEST
 
-  nsContentPermissionRequestProxy();
+  explicit nsContentPermissionRequestProxy(ContentPermissionRequestParent* parent);
 
-  nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests,
-                ContentPermissionRequestParent* parent);
+  nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests);
 
   void OnParentDestroyed();
 
   void NotifyVisibility(const bool& aIsVisible);
 
 private:
   class nsContentPermissionRequesterProxy final : public nsIContentPermissionRequester {
   public:
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8835,16 +8835,36 @@ nsContentUtils::IsThirdPartyWindowOrChan
                                                   &thirdParty);
   }
 
   return thirdParty;
 }
 
 // static public
 bool
+nsContentUtils::IsTrackingResourceWindow(nsPIDOMWindowInner* aWindow)
+{
+  MOZ_ASSERT(aWindow);
+
+  nsIDocument* document = aWindow->GetExtantDoc();
+  if (!document) {
+    return false;
+  }
+
+  nsCOMPtr<nsIHttpChannel> httpChannel =
+    do_QueryInterface(document->GetChannel());
+  if (!httpChannel) {
+    return false;
+  }
+
+  return httpChannel->GetIsTrackingResource();
+}
+
+// static public
+bool
 nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
                                               nsIChannel* aChannel,
                                               nsIURI* aURI)
 {
   if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
     return false;
   }
 
@@ -9630,17 +9650,18 @@ nsContentUtils::SerializeNodeToMarkup(ns
 
 bool
 nsContentUtils::IsSpecificAboutPage(JSObject* aGlobal, const char* aUri)
 {
   // aUri must start with about: or this isn't the right function to be using.
   MOZ_ASSERT(strncmp(aUri, "about:", 6) == 0);
 
   // Make sure the global is a window
-  nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(aGlobal);
+  MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal));
+  nsGlobalWindowInner* win = xpc::WindowOrNull(aGlobal);
   if (!win) {
     return false;
   }
 
   nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal();
   NS_ENSURE_TRUE(principal, false);
   nsCOMPtr<nsIURI> uri;
   principal->GetURI(getter_AddRefs(uri));
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2960,16 +2960,22 @@ public:
   /*
    * Returns true if this window/channel is a 3rd party context.
    */
   static bool IsThirdPartyWindowOrChannel(nsPIDOMWindowInner* aWindow,
                                           nsIChannel* aChannel,
                                           nsIURI* aURI);
 
   /*
+   * Returns true if this window's channel has been marked as a tracking
+   * resource.
+   */
+  static bool IsTrackingResourceWindow(nsPIDOMWindowInner* aWindow);
+
+  /*
    * Serializes a HTML nsINode into its markup representation.
    */
   static bool SerializeNodeToMarkup(nsINode* aRoot,
                                     bool aDescendentsOnly,
                                     nsAString& aOut);
 
   /*
    * Returns true iff the provided JSObject is a global, and its URI matches
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2038,18 +2038,18 @@ nsDOMWindowUtils::SendQueryContentEvent(
       queryEvent.Init(options);
       break;
   }
 
   nsEventStatus status;
   nsresult rv = targetWidget->DispatchEvent(&queryEvent, status);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  auto* result = new nsQueryContentEventResult();
-  result->SetEventResult(widget, queryEvent);
+  auto* result = new nsQueryContentEventResult(queryEvent);
+  result->SetEventResult(widget);
   NS_ADDREF(*aResult = result);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset,
                                         uint32_t aLength,
                                         uint32_t aAdditionalFlags,
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2594,19 +2594,20 @@ WarnIfSandboxIneffective(nsIDocShell* aD
 
 bool
 nsIDocument::IsSynthesized() {
   nsCOMPtr<nsILoadInfo> loadInfo = mChannel ? mChannel->GetLoadInfo() : nullptr;
   return loadInfo && loadInfo->GetServiceWorkerTaintingSynthesized();
 }
 
 bool
-nsDocument::IsShadowDOMEnabled(JSContext* aCx, JSObject* aObject)
-{
-  nsCOMPtr<nsPIDOMWindowInner> window = xpc::WindowGlobalOrNull(aObject);
+nsDocument::IsShadowDOMEnabled(JSContext* aCx, JSObject* aGlobal)
+{
+  MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal));
+  nsCOMPtr<nsPIDOMWindowInner> window = xpc::WindowOrNull(aGlobal);
 
   nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
   if (!doc) {
     return false;
   }
 
   return doc->IsShadowDOMEnabled();
 }
@@ -4626,17 +4627,17 @@ nsIDocument::SetScriptGlobalObject(nsISc
     mHasHadDefaultView = true;
 #ifdef DEBUG
     if (!mWillReparent) {
       // We really shouldn't have a wrapper here but if we do we need to make sure
       // it has the correct parent.
       JSObject *obj = GetWrapperPreserveColor();
       if (obj) {
         JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject();
-        NS_ASSERTION(js::GetGlobalForObjectCrossCompartment(obj) == newScope,
+        NS_ASSERTION(JS::GetNonCCWObjectGlobal(obj) == newScope,
                      "Wrong scope, this is really bad!");
       }
     }
 #endif
 
     if (mAllowDNSPrefetch) {
       nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
       if (docShell) {
@@ -4708,22 +4709,19 @@ nsIDocument::SetScriptGlobalObject(nsISc
   }
 
   // The global in the template contents owner document should be the same.
   if (mTemplateContentsOwner && mTemplateContentsOwner != this) {
     mTemplateContentsOwner->SetScriptGlobalObject(aScriptGlobalObject);
   }
 
   if (!mMaybeServiceWorkerControlled && mDocumentContainer && mScriptGlobalObject && GetChannel()) {
-    nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
-    uint32_t loadType;
-    docShell->GetLoadType(&loadType);
 
     // If we are shift-reloaded, don't associate with a ServiceWorker.
-    if (IsForceReloadType(loadType)) {
+    if (mDocumentContainer->IsForceReloading()) {
       NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
       return;
     }
 
     mMaybeServiceWorkerControlled = true;
   }
 }
 
@@ -12448,19 +12446,20 @@ nsIDocument::MaybeAllowStorageForOpener(
     return;
   }
 
   nsPIDOMWindowInner* openerInner = outerOpener->GetCurrentInnerWindow();
   if (NS_WARN_IF(!openerInner)) {
     return;
   }
 
-  // No 3rd party.
+  // No 3rd party or no tracking resource.
   if (!nsContentUtils::IsThirdPartyWindowOrChannel(openerInner, nullptr,
-                                                   nullptr)) {
+                                                   nullptr) ||
+      !nsContentUtils::IsTrackingResourceWindow(openerInner)) {
     return;
   }
 
   nsCOMPtr<nsIURI> uri = GetDocumentURI();
   if (NS_WARN_IF(!uri)) {
     return;
   }
 
@@ -12570,16 +12569,18 @@ ArrayContainsTable(const nsTArray<nsCStr
 }
 
 namespace {
 
 // An object to store all preferences we need for flash blocking feature.
 struct PrefStore
 {
   PrefStore()
+    : mFlashBlockEnabled(false)
+    , mPluginsHttpOnly(false)
   {
     Preferences::AddBoolVarCache(&mFlashBlockEnabled,
                                  "plugins.flashBlock.enabled");
     Preferences::AddBoolVarCache(&mPluginsHttpOnly,
                                  "plugins.http_https_only");
 
     // We only need to register string-typed preferences.
     Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowTable", this);
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -189,18 +189,18 @@ public:
                                        bool aRequiredAdded) override;
   virtual bool GetValueMissingState(const nsAString& aName) const override;
   virtual void SetValueMissingState(const nsAString& aName, bool aValue) override;
 
   // for radio group
   nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
   nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
 
-  // Check whether shadow DOM is enabled for the global of aObject.
-  static bool IsShadowDOMEnabled(JSContext* aCx, JSObject* aObject);
+  // Check whether shadow DOM is enabled for aGlobal.
+  static bool IsShadowDOMEnabled(JSContext* aCx, JSObject* aGlobal);
   // Check whether shadow DOM is enabled for the document this node belongs to.
   static bool IsShadowDOMEnabled(const nsINode* aNode);
 
 public:
   using mozilla::dom::DocumentOrShadowRoot::GetElementById;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagName;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagNameNS;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByClassName;
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -208,16 +208,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(nsDocumentEncoder,
                          mDocument, mSelection, mRange, mNode, mSerializer,
                          mCommonParent)
 
 nsDocumentEncoder::nsDocumentEncoder()
   : mEncoding(nullptr)
+  , mIsCopying(false)
   , mCachedBuffer(nullptr)
 {
   Initialize();
   mMimeType.AssignLiteral("text/plain");
 }
 
 void nsDocumentEncoder::Initialize(bool aClearCachedSerializer)
 {
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -20,17 +20,17 @@
 #include "nsIContentInlines.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 #include "nsIBaseWindow.h"
 #include "nsIBrowser.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsUnicharUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
@@ -467,19 +467,17 @@ nsFrameLoader::ReallyStartLoadingInterna
   }
   NS_ASSERTION(mDocShell,
                "MaybeCreateDocShell succeeded with a null mDocShell");
 
   // Just to be safe, recheck uri.
   rv = CheckURILoad(mURIToLoad, mTriggeringPrincipal);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
-  mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
-  NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
+  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
 
   loadInfo->SetOriginalFrameSrc(mLoadingOriginalSrc);
   mLoadingOriginalSrc = false;
 
   // If this frame is sandboxed with respect to origin we will set it up with
   // a null principal later in nsDocShell::DoURILoad.
   // We do it there to correctly sandbox content that was loaded into
   // the frame via other methods than the src attribute.
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -506,18 +506,16 @@ private:
   // attribute of the frame element.
   bool mLoadingOriginalSrc : 1;
 
   bool mRemoteBrowserShown : 1;
   bool mRemoteFrame : 1;
   bool mClipSubdocument : 1;
   bool mClampScrollPosition : 1;
   bool mObservingOwnerContent : 1;
-
-  bool mFreshProcess : 1;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsFrameLoader, NS_FRAMELOADER_IID)
 
 inline nsISupports*
 ToSupports(nsFrameLoader* aFrameLoader)
 {
   return aFrameLoader;
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -8207,17 +8207,21 @@ nsGlobalWindowInner::SaveFirstPartyStora
 }
 
 /* static */ void
 nsGlobalWindowInner::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aPrincipal,
                                                                                 const nsCString& aParentOrigin,
                                                                                 const nsCString& aGrantedOrigin)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
-  MOZ_ASSERT(aPrincipal);
+
+  if (NS_WARN_IF(!aPrincipal)) {
+    // The child process is sending something wrong. Let's ignore it.
+    return;
+  }
 
   nsAutoCString origin;
   nsresult rv = aPrincipal->GetOriginNoSuffix(origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -54,16 +54,17 @@
 #include "nsWindowSizes.h"
 #include "WindowNamedPropertiesHandler.h"
 #include "nsFrameSelection.h"
 #include "nsNetUtil.h"
 #include "nsVariant.h"
 #include "nsPrintfCString.h"
 #include "mozilla/intl/LocaleService.h"
 #include "WindowDestroyedEvent.h"
+#include "nsDocShellLoadInfo.h"
 
 // Helper Classes
 #include "nsJSUtils.h"
 #include "jsapi.h"              // for JSAutoRequest
 #include "js/Wrapper.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsReadableUtils.h"
 #include "nsJSEnvironment.h"
@@ -5462,17 +5463,17 @@ nsGlobalWindowOuter::OpenOuter(const nsA
 {
   nsCOMPtr<nsPIDOMWindowOuter> window;
   aError = OpenJS(aUrl, aName, aOptions, getter_AddRefs(window));
   return window.forget();
 }
 
 nsresult
 nsGlobalWindowOuter::Open(const nsAString& aUrl, const nsAString& aName,
-                          const nsAString& aOptions, nsIDocShellLoadInfo* aLoadInfo,
+                          const nsAString& aOptions, nsDocShellLoadInfo* aLoadInfo,
                           bool aForceNoOpener, nsPIDOMWindowOuter **_retval)
 {
   return OpenInternal(aUrl, aName, aOptions,
                       false,          // aDialog
                       false,          // aContentModal
                       true,           // aCalledNoScript
                       false,          // aDoJSFixups
                       true,           // aNavigate
@@ -6847,17 +6848,17 @@ public:
 
 nsresult
 nsGlobalWindowOuter::OpenInternal(const nsAString& aUrl, const nsAString& aName,
                                   const nsAString& aOptions, bool aDialog,
                                   bool aContentModal, bool aCalledNoScript,
                                   bool aDoJSFixups, bool aNavigate,
                                   nsIArray *argv,
                                   nsISupports *aExtraArgument,
-                                  nsIDocShellLoadInfo* aLoadInfo,
+                                  nsDocShellLoadInfo* aLoadInfo,
                                   bool aForceNoOpener,
                                   nsPIDOMWindowOuter **aReturn)
 {
 #ifdef DEBUG
   uint32_t argc = 0;
   if (argv)
       argv->GetLength(&argc);
 #endif
@@ -6892,43 +6893,47 @@ nsGlobalWindowOuter::OpenInternal(const 
     while (tok.hasMoreTokens()) {
       if (tok.nextToken().EqualsLiteral("noopener")) {
         forceNoOpener = true;
         break;
       }
     }
   }
 
+  bool windowExists = WindowExists(aName, forceNoOpener, !aCalledNoScript);
+
   // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
   // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
   // But note that if you change this to GetEntryGlobal(), say, then
   // OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
   const bool checkForPopup = !nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
-    !aDialog && !WindowExists(aName, forceNoOpener, !aCalledNoScript);
+    !aDialog && !windowExists;
 
   // Note: the Void handling here is very important, because the window watcher
   // expects a null URL string (not an empty string) if there is no URL to load.
   nsCString url;
   url.SetIsVoid(true);
   nsresult rv = NS_OK;
 
+  nsCOMPtr<nsIURI> uri;
+
   // It's important to do this security check before determining whether this
   // window opening should be blocked, to ensure that we don't FireAbuseEvents
   // for a window opening that wouldn't have succeeded in the first place.
   if (!aUrl.IsEmpty()) {
     AppendUTF16toUTF8(aUrl, url);
 
     // It's safe to skip the security check below if we're not a dialog
     // because window.openDialog is not callable from content script.  See bug
     // 56851.
     //
     // If we're not navigating, we assume that whoever *does* navigate the
     // window will do a security check of their own.
     if (!url.IsVoid() && !aDialog && aNavigate)
-      rv = SecurityCheckURL(url.get());
+      rv = SecurityCheckURL(url.get(), getter_AddRefs(uri));
   }
 
   if (NS_FAILED(rv))
     return rv;
 
   PopupControlState abuseLevel = GetPopupControlState();
   if (checkForPopup) {
     abuseLevel = RevisePopupAbuseLevel(abuseLevel);
@@ -7020,16 +7025,20 @@ nsGlobalWindowOuter::OpenInternal(const 
 
     }
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // success!
 
+  if (!aCalledNoScript && !windowExists && uri) {
+    MaybeAllowStorageForOpenedWindow(uri);
+  }
+
   NS_ENSURE_TRUE(domReturn, NS_OK);
   nsCOMPtr<nsPIDOMWindowOuter> outerReturn =
     nsPIDOMWindowOuter::From(domReturn);
   outerReturn.swap(*aReturn);
 
   if (aDoJSFixups) {
     nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
     if (!chrome_win) {
@@ -7044,16 +7053,39 @@ nsGlobalWindowOuter::OpenInternal(const 
       nsCOMPtr<nsIDocument> doc = (*aReturn)->GetDoc();
       Unused << doc;
     }
   }
 
   return rv;
 }
 
+void
+nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI)
+{
+  nsGlobalWindowInner *inner = GetCurrentInnerWindowInternal();
+  if (NS_WARN_IF(!inner)) {
+    return;
+  }
+
+  // No 3rd party or no tracking resource.
+  if (!nsContentUtils::IsThirdPartyWindowOrChannel(inner, nullptr, nullptr) ||
+      !nsContentUtils::IsTrackingResourceWindow(inner)) {
+    return;
+  }
+
+  nsAutoString origin;
+  nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  inner->AddFirstPartyStorageAccessGrantedFor(origin, true);
+}
+
 //*****************************************************************************
 // nsGlobalWindowOuter: Helper Functions
 //*****************************************************************************
 
 already_AddRefed<nsIDocShellTreeOwner>
 nsGlobalWindowOuter::GetTreeOwner()
 {
   // If there's no docShellAsItem, this window must have been closed,
@@ -7103,17 +7135,17 @@ nsGlobalWindowOuter::GetScrollFrame()
   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   if (presShell) {
     return presShell->GetRootScrollFrameAsScrollable();
   }
   return nullptr;
 }
 
 nsresult
-nsGlobalWindowOuter::SecurityCheckURL(const char *aURL)
+nsGlobalWindowOuter::SecurityCheckURL(const char *aURL, nsIURI** aURI)
 {
   nsCOMPtr<nsPIDOMWindowInner> sourceWindow = do_QueryInterface(GetEntryGlobal());
   if (!sourceWindow) {
     sourceWindow = GetCurrentInnerWindow();
   }
   AutoJSContext cx;
   nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
   JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
@@ -7136,16 +7168,17 @@ nsGlobalWindowOuter::SecurityCheckURL(co
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   if (NS_FAILED(nsContentUtils::GetSecurityManager()->
         CheckLoadURIFromScript(cx, uri))) {
     return NS_ERROR_FAILURE;
   }
 
+  uri.forget(aURI);
   return NS_OK;
 }
 
 bool
 nsGlobalWindowOuter::IsPrivateBrowsing()
 {
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
   return loadContext && loadContext->UsePrivateBrowsing();
@@ -7570,16 +7603,17 @@ nsGlobalWindowOuter::AbstractMainThreadF
   if (GetDocGroup()) {
     return GetDocGroup()->AbstractMainThreadFor(aCategory);
   }
   return DispatcherTrait::AbstractMainThreadFor(aCategory);
 }
 
 nsGlobalWindowOuter::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
   nsGlobalWindowOuter* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+  : mSavedDialogsEnabled(false)
 {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
   MOZ_ASSERT(aWindow);
   nsGlobalWindowOuter* topWindowOuter = aWindow->GetScriptableTopInternal();
   if (!topWindowOuter) {
     NS_ERROR("nsGlobalWindowOuter::TemporarilyDisableDialogs used without a top "
              "window?");
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -67,16 +67,17 @@ class nsIControllers;
 class nsIJSID;
 class nsIScriptContext;
 class nsIScriptTimeoutHandler;
 class nsITabChild;
 class nsITimeoutHandler;
 class nsIWebBrowserChrome;
 class mozIDOMWindowProxy;
 
+class nsDocShellLoadInfo;
 class nsDOMWindowList;
 class nsScreen;
 class nsHistory;
 class nsGlobalWindowObserver;
 class nsGlobalWindowInner;
 class nsDOMWindowUtils;
 class nsIIdleService;
 struct nsRect;
@@ -606,17 +607,17 @@ public:
   mozilla::dom::Element* GetFrameElement() override;
   already_AddRefed<nsPIDOMWindowOuter>
   OpenOuter(const nsAString& aUrl,
             const nsAString& aName,
             const nsAString& aOptions,
             mozilla::ErrorResult& aError);
   nsresult Open(const nsAString& aUrl, const nsAString& aName,
                 const nsAString& aOptions,
-                nsIDocShellLoadInfo* aLoadInfo,
+                nsDocShellLoadInfo* aLoadInfo,
                 bool aForceNoOpener,
                 nsPIDOMWindowOuter **_retval) override;
   mozilla::dom::Navigator* GetNavigator() override;
 
 #if defined(MOZ_WIDGET_ANDROID)
   int16_t Orientation(mozilla::dom::CallerType aCallerType) const;
 #endif
 
@@ -892,26 +893,26 @@ private:
                         const nsAString& aOptions,
                         bool aDialog,
                         bool aContentModal,
                         bool aCalledNoScript,
                         bool aDoJSFixups,
                         bool aNavigate,
                         nsIArray *argv,
                         nsISupports *aExtraArgument,
-                        nsIDocShellLoadInfo* aLoadInfo,
+                        nsDocShellLoadInfo* aLoadInfo,
                         bool aForceNoOpener,
                         nsPIDOMWindowOuter **aReturn);
 
 public:
   // Helper Functions
   already_AddRefed<nsIDocShellTreeOwner> GetTreeOwner();
   already_AddRefed<nsIBaseWindow> GetTreeOwnerWindow();
   already_AddRefed<nsIWebBrowserChrome> GetWebBrowserChrome();
-  nsresult SecurityCheckURL(const char *aURL);
+  nsresult SecurityCheckURL(const char *aURL, nsIURI** aURI);
   bool IsPrivateBrowsing();
 
   bool PopupWhitelisted();
   PopupControlState RevisePopupAbuseLevel(PopupControlState);
   void     FireAbuseEvents(const nsAString &aPopupURL,
                            const nsAString &aPopupWindowName,
                            const nsAString &aPopupWindowFeatures);
 
@@ -1048,16 +1049,18 @@ private:
   friend class nsPIDOMWindowOuter;
 
   mozilla::dom::TabGroup* TabGroupOuter();
 
   void SetIsBackgroundInternal(bool aIsBackground);
 
   nsresult GetInterfaceInternal(const nsIID& aIID, void** aSink);
 
+  void MaybeAllowStorageForOpenedWindow(nsIURI* aURI);
+
 public:
   // Dispatch a runnable related to the global.
   virtual nsresult Dispatch(mozilla::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsISerialEventTarget*
   EventTargetFor(mozilla::TaskCategory aCategory) const override;
 
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1290,17 +1290,17 @@ CheckForOutdatedParent(nsINode* aParent,
 {
   if (JSObject* existingObjUnrooted = aNode->GetWrapper()) {
     JS::Rooted<JSObject*> existingObj(RootingCx(), existingObjUnrooted);
 
     AutoJSContext cx;
     nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject();
     MOZ_ASSERT(global);
 
-    if (js::GetGlobalForObjectCrossCompartment(existingObj) !=
+    if (JS::GetNonCCWObjectGlobal(existingObj) !=
         global->GetGlobalJSObject()) {
       JSAutoRealm ar(cx, existingObj);
       ReparentWrapper(cx, existingObj, aError);
     }
   }
 }
 
 static nsresult
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -146,19 +146,16 @@ private:
   void Destroy();
 
   JS::Heap<JSObject*> mWindowProxy;
 
   bool mIsInitialized;
   bool mGCOnDestruction;
   bool mProcessingScriptTag;
 
-  PRTime mModalStateTime;
-  uint32_t mModalStateDepth;
-
   // mGlobalObjectRef ensures that the outer window stays alive as long as the
   // context does. It is eventually collected by the cycle collector.
   nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef;
 
   static bool DOMOperationCallback(JSContext *cx);
 };
 
 namespace mozilla {
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -11,17 +11,16 @@
 
 // Interface headers
 #include "imgLoader.h"
 #include "nsIClassOfService.h"
 #include "nsIConsoleService.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellLoadInfo.h"
 #include "nsIDocument.h"
 #include "nsIExternalProtocolHandler.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIObjectFrame.h"
 #include "nsIOService.h"
 #include "nsIPermissionManager.h"
 #include "nsPluginHost.h"
 #include "nsPluginInstanceOwner.h"
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -24,17 +24,17 @@
 
 class nsDOMWindowList;
 class nsGlobalWindowInner;
 class nsGlobalWindowOuter;
 class nsIArray;
 class nsIContent;
 class nsICSSDeclaration;
 class nsIDocShell;
-class nsIDocShellLoadInfo;
+class nsDocShellLoadInfo;
 class nsIDocument;
 class nsIIdleObserver;
 class nsIPrincipal;
 class nsIScriptTimeoutHandler;
 class nsISerialEventTarget;
 class nsIURI;
 class nsPIDOMWindowInner;
 class nsPIDOMWindowOuter;
@@ -1120,17 +1120,17 @@ public:
 
   virtual nsDOMWindowList* GetFrames() = 0;
 
   // aLoadInfo will be passed on through to the windowwatcher.
   // aForceNoOpener will act just like a "noopener" feature in aOptions except
   //                will not affect any other window features.
   virtual nsresult Open(const nsAString& aUrl, const nsAString& aName,
                         const nsAString& aOptions,
-                        nsIDocShellLoadInfo* aLoadInfo,
+                        nsDocShellLoadInfo* aLoadInfo,
                         bool aForceNoOpener,
                         nsPIDOMWindowOuter **_retval) = 0;
   virtual nsresult OpenDialog(const nsAString& aUrl, const nsAString& aName,
                               const nsAString& aOptions,
                               nsISupports* aExtraArgument,
                               nsPIDOMWindowOuter** _retval) = 0;
 
   virtual nsresult GetInnerWidth(int32_t* aWidth) = 0;
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -76,17 +76,20 @@ nsresult
 NS_NewPlainTextSerializer(nsIContentSerializer** aSerializer)
 {
   RefPtr<nsPlainTextSerializer> it = new nsPlainTextSerializer();
   it.forget(aSerializer);
   return NS_OK;
 }
 
 nsPlainTextSerializer::nsPlainTextSerializer()
-  : kSpace(NS_LITERAL_STRING(" ")) // Init of "constant"
+  : mFlags(0)
+  , mFloatingLines(-1)
+  , mLineBreakDue(false)
+  , kSpace(NS_LITERAL_STRING(" ")) // Init of "constant"
 {
 
   mOutputString = nullptr;
   mHeadLevel = 0;
   mAtFirstColumn = true;
   mIndent = 0;
   mCiteQuoteLevel = 0;
   mStructs = true;       // will be read from prefs later
--- a/dom/base/nsQueryContentEventResult.cpp
+++ b/dom/base/nsQueryContentEventResult.cpp
@@ -46,20 +46,28 @@ static bool IsRectRelatedPropertyAvailab
 NS_INTERFACE_MAP_BEGIN(nsQueryContentEventResult)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIQueryContentEventResult)
   NS_INTERFACE_MAP_ENTRY(nsIQueryContentEventResult)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsQueryContentEventResult)
 NS_IMPL_RELEASE(nsQueryContentEventResult)
 
-nsQueryContentEventResult::nsQueryContentEventResult()
-  : mEventMessage(eVoidEvent)
-  , mSucceeded(false)
+nsQueryContentEventResult::nsQueryContentEventResult(mozilla::WidgetQueryContentEvent &aEvent)
+  : mEventMessage(aEvent.mMessage)
+  , mOffset(aEvent.mReply.mOffset)
+  , mTentativeCaretOffset(aEvent.mReply.mTentativeCaretOffset)
+  , mString(aEvent.mReply.mString)
+  , mRect(aEvent.mReply.mRect)
+  , mRectArray(std::move(aEvent.mReply.mRectArray))
+  , mSucceeded(aEvent.mSucceeded)
+  , mReversed(aEvent.mReply.mReversed)
 {
+  // Mark as result that is longer used.
+  aEvent.mSucceeded = false;
 }
 
 nsQueryContentEventResult::~nsQueryContentEventResult()
 {
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetOffset(uint32_t* aOffset)
@@ -218,30 +226,18 @@ nsQueryContentEventResult::GetCharacterR
   *aTop = mRectArray[aOffset].y;
   *aWidth = mRectArray[aOffset].Width();
   *aHeight = mRectArray[aOffset].Height();
 
   return NS_OK;
 }
 
 void
-nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget,
-                                          WidgetQueryContentEvent &aEvent)
+nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget)
 {
-  mEventMessage = aEvent.mMessage;
-  mSucceeded = aEvent.mSucceeded;
-  mReversed = aEvent.mReply.mReversed;
-  mRect = aEvent.mReply.mRect;
-  mOffset = aEvent.mReply.mOffset;
-  mTentativeCaretOffset = aEvent.mReply.mTentativeCaretOffset;
-  mString = aEvent.mReply.mString;
-  mRectArray = std::move(aEvent.mReply.mRectArray);
-  // Mark as result that is longer used.
-  aEvent.mSucceeded = false;
-
   if (!IsRectRelatedPropertyAvailable(mEventMessage) ||
       !aWidget || !mSucceeded) {
     return;
   }
 
   nsIWidget* topWidget = aWidget->GetTopLevelWidget();
   if (!topWidget || topWidget == aWidget) {
     return;
--- a/dom/base/nsQueryContentEventResult.h
+++ b/dom/base/nsQueryContentEventResult.h
@@ -14,22 +14,21 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 
 class nsIWidget;
 
 class nsQueryContentEventResult final : public nsIQueryContentEventResult
 {
 public:
-  nsQueryContentEventResult();
+  explicit nsQueryContentEventResult(mozilla::WidgetQueryContentEvent& aEvent);
   NS_DECL_ISUPPORTS
   NS_DECL_NSIQUERYCONTENTEVENTRESULT
 
-  void SetEventResult(nsIWidget* aWidget,
-                      mozilla::WidgetQueryContentEvent& aEvent);
+  void SetEventResult(nsIWidget* aWidget);
 
 protected:
   ~nsQueryContentEventResult();
 
   mozilla::EventMessage mEventMessage;
 
   uint32_t mOffset;
   uint32_t mTentativeCaretOffset;
--- a/dom/base/nsSyncLoadService.cpp
+++ b/dom/base/nsSyncLoadService.cpp
@@ -34,17 +34,21 @@ using mozilla::net::ReferrerPolicy;
  */
 
 class nsSyncLoader : public nsIStreamListener,
                      public nsIChannelEventSink,
                      public nsIInterfaceRequestor,
                      public nsSupportsWeakReference
 {
 public:
-    nsSyncLoader() : mLoading(false) {}
+    nsSyncLoader()
+      : mLoading(false)
+      , mAsyncLoadStatus(NS_ERROR_NOT_INITIALIZED)
+    {
+    }
 
     NS_DECL_ISUPPORTS
 
     nsresult LoadDocument(nsIChannel* aChannel,
                           bool aChannelIsSync, bool aForceToXML,
                           ReferrerPolicy aReferrerPolicy,
                           nsIDocument** aResult);
 
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -43,16 +43,20 @@ NS_NewXHTMLContentSerializer(nsIContentS
 {
   RefPtr<nsXHTMLContentSerializer> it = new nsXHTMLContentSerializer();
   it.forget(aSerializer);
   return NS_OK;
 }
 
 nsXHTMLContentSerializer::nsXHTMLContentSerializer()
   : mIsHTMLSerializer(false)
+  , mIsCopying(false)
+  , mDisableEntityEncoding(0)
+  , mRewriteEncodingDeclaration(false)
+  , mIsFirstChildOfOL(false)
 {
 }
 
 nsXHTMLContentSerializer::~nsXHTMLContentSerializer()
 {
   NS_ASSERTION(mOLStateStack.IsEmpty(), "Expected OL State stack to be empty");
 }
 
--- a/dom/base/nsXHTMLContentSerializer.h
+++ b/dom/base/nsXHTMLContentSerializer.h
@@ -104,17 +104,16 @@ private:
 protected:
 
   /*
    * isHTMLParser should be set to true by the HTML parser which inherits from
    * this class. It avoids to redefine methods just for few changes.
    */
   bool          mIsHTMLSerializer;
 
-  bool          mDoHeader;
   bool          mIsCopying; // Set to true only while copying
 
   /*
    * mDisableEntityEncoding is higher than 0 while the serializer is serializing
    * the content of a element whose content is considerd CDATA by the
    * serializer (such elements are 'script', 'style', 'noscript' and
    * possibly others in XHTML) This doesn't have anything to do with if the
    * element is defined as CDATA in the DTD, it simply means we'll
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -477,17 +477,17 @@ public:
   T* get() const {
     MOZ_ASSERT(inited);
     MOZ_ASSERT(ptr);
     return ptr;
   }
 
 protected:
   // ptr is left uninitialized for optimization purposes.
-  T* ptr;
+  MOZ_INIT_OUTSIDE_CTOR T* ptr;
 #ifdef DEBUG
   bool inited;
 #endif
 };
 
 // Class for representing sequences in arguments.  We use a non-auto array
 // because that allows us to use sequences of sequences and the like.  This
 // needs to be fallible because web content controls the length of the array,
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -169,17 +169,21 @@ ThrowNoSetterArg(JSContext* aCx, prototy
 }
 
 } // namespace dom
 
 namespace binding_danger {
 
 template<typename CleanupPolicy>
 struct TErrorResult<CleanupPolicy>::Message {
-  Message() { MOZ_COUNT_CTOR(TErrorResult::Message); }
+  Message()
+    : mErrorNumber(dom::Err_Limit)
+  {
+    MOZ_COUNT_CTOR(TErrorResult::Message);
+  }
   ~Message() { MOZ_COUNT_DTOR(TErrorResult::Message); }
 
   nsTArray<nsString> mArgs;
   dom::ErrNum mErrorNumber;
 
   bool HasCorrectNumberOfArguments()
   {
     return GetErrorArgCount(mErrorNumber) == mArgs.Length();
@@ -1640,17 +1644,17 @@ XrayResolveProperty(JSContext* cx, JS::H
 
 static bool
 ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
                               JS::Handle<JSObject*> obj,
                               size_t protoAndIfaceCacheIndex, unsigned attrs,
                               JS::MutableHandle<JS::PropertyDescriptor> desc,
                               bool& cacheOnHolder)
 {
-  JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
+  JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj));
   {
     JSAutoRealm ar(cx, global);
     ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
     // This function is called when resolving the "constructor" and "prototype"
     // properties of Xrays for DOM prototypes and constructors respectively.
     // This means the relevant Xray exists, which means its _target_ exists.
     // And that means we managed to successfullly create the prototype or
     // constructor, respectively, and hence must have managed to create the
@@ -3047,17 +3051,17 @@ struct MaybeGlobalThisPolicy : public No
     // Here we have to allow null/undefined.
     return aArgs.thisv().isObject() || aArgs.thisv().isNullOrUndefined();
   }
 
   static MOZ_ALWAYS_INLINE JSObject* ExtractThisObject(const JS::CallArgs& aArgs)
   {
     return aArgs.thisv().isObject() ?
       &aArgs.thisv().toObject() :
-      js::GetGlobalForObjectCrossCompartment(&aArgs.callee());
+      JS::GetNonCCWObjectGlobal(&aArgs.callee());
   }
 
   // We want the MaybeUnwrapThisObject of NormalThisPolicy.
 
   // We want the HandleInvalidThis of NormalThisPolicy.
 };
 
 // There are some LenientThis things on globals, so we inherit from
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1659,17 +1659,19 @@ FindAssociatedGlobal(JSContext* cx, T* p
   }
 
   JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
   if (!obj) {
     return nullptr;
   }
   MOZ_ASSERT(JS::ObjectIsNotGray(obj));
 
-  obj = js::GetGlobalForObjectCrossCompartment(obj);
+  // The object is never a CCW but it may not be in the current compartment of
+  // the JSContext.
+  obj = JS::GetNonCCWObjectGlobal(obj);
 
   if (!useXBLScope) {
     return obj;
   }
 
   // If useXBLScope is true, it means that the canonical reflector for this
   // native object should live in the content XBL scope. Note that we never put
   // anonymous content inside an add-on scope.
@@ -2407,17 +2409,17 @@ XrayOwnPropertyKeys(JSContext* cx, JS::H
  * cx should be in the Xray's compartment.
  * obj is the target object of the Xray, a binding's instance object or an
  *     interface or interface prototype object.
  */
 inline bool
 XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
                    JS::MutableHandle<JSObject*> protop)
 {
-  JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
+  JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj));
   {
     JSAutoRealm ar(cx, global);
     const DOMJSClass* domClass = GetDOMClass(obj);
     if (domClass) {
       ProtoHandleGetter protoGetter = domClass->mGetProto;
       if (protoGetter) {
         protop.set(protoGetter(cx));
       } else {
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -517,17 +517,20 @@ private:
 
     // mDOMExceptionInfo is set by ThrowDOMException and reported (and
     // deallocated) by SetPendingDOMException.
     DOMExceptionInfo* mDOMExceptionInfo; // valid when IsDOMException()
 
     // |mJSException| has a non-trivial constructor and therefore MUST be
     // placement-new'd into existence.
     MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
-    Extra() {}
+    Extra()
+      : mMessage(nullptr)
+    {
+    }
     MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
   } mExtra;
 
   Message* InitMessage(Message* aMessage) {
     // The |new| here switches the active arm of |mExtra|, from the compiler's
     // point of view.  Mere assignment *won't* necessarily do the right thing!
     new (&mExtra.mMessage) Message*(aMessage);
     return mExtra.mMessage;
--- a/dom/bindings/FakeString.h
+++ b/dom/bindings/FakeString.h
@@ -106,19 +106,19 @@ operator const nsAString& () const {
   }
 
 private:
   nsAString* ToAStringPtr() {
     return reinterpret_cast<nsString*>(this);
   }
 
   // mData is left uninitialized for optimization purposes.
-  nsString::char_type* mData;
+  MOZ_INIT_OUTSIDE_CTOR nsString::char_type* mData;
   // mLength is left uninitialized for optimization purposes.
-  nsString::size_type mLength;
+  MOZ_INIT_OUTSIDE_CTOR nsString::size_type mLength;
   nsString::DataFlags mDataFlags;
   nsString::ClassFlags mClassFlags;
 
   static const size_t sInlineCapacity = 64;
   nsString::char_type mInlineStorage[sInlineCapacity];
 
   FakeString(const FakeString& other) = delete;
   void operator=(const FakeString& other) = delete;
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -216,16 +216,17 @@ struct ArrayBufferView_base
 {
 private:
   typedef TypedArray_base<uint8_t, UnwrapArray, GetLengthAndDataAndSharedness>
           Base;
 
 public:
   ArrayBufferView_base()
     : Base()
+    , mType(js::Scalar::MaxTypedArrayViewType)
   {
   }
 
   ArrayBufferView_base(ArrayBufferView_base&& aOther)
     : Base(std::move(aOther)),
       mType(aOther.mType)
   {
     aOther.mType = js::Scalar::MaxTypedArrayViewType;
--- a/dom/cache/SavedTypes.h
+++ b/dom/cache/SavedTypes.h
@@ -17,26 +17,44 @@
 #include "nsIOutputStream.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 struct SavedRequest
 {
-  SavedRequest() : mHasBodyId(false) { mValue.body() = void_t(); }
+  SavedRequest()
+    : mHasBodyId(false)
+    , mCacheId(0)
+  {
+    mBodyId.m0 = 0;
+    mBodyId.m1 = 0;
+    mBodyId.m2 = 0;
+    memset(mBodyId.m3, 0, sizeof(mBodyId.m3));
+    mValue.body() = void_t();
+  }
   CacheRequest mValue;
   bool mHasBodyId;
   nsID mBodyId;
   CacheId mCacheId;
 };
 
 struct SavedResponse
 {
-  SavedResponse() : mHasBodyId(false) { mValue.body() = void_t(); }
+  SavedResponse()
+    : mHasBodyId(false)
+    , mCacheId(0)
+  {
+    mBodyId.m0 = 0;
+    mBodyId.m1 = 0;
+    mBodyId.m2 = 0;
+    memset(mBodyId.m3, 0, sizeof(mBodyId.m3));
+    mValue.body() = void_t();
+  }
   CacheResponse mValue;
   bool mHasBodyId;
   nsID mBodyId;
   CacheId mCacheId;
 };
 
 } // namespace cache
 } // namespace dom
--- a/dom/clients/manager/ClientNavigateOpChild.cpp
+++ b/dom/clients/manager/ClientNavigateOpChild.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientNavigateOpChild.h"
 
 #include "ClientState.h"
 #include "mozilla/Unused.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
@@ -211,26 +211,21 @@ ClientNavigateOpChild::DoNavigate(const 
 
   nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
   nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
   if (!docShell || !webProgress) {
     ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
     return ref.forget();
   }
 
-  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
-  rv = docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
-  if (NS_FAILED(rv)) {
-    ref = ClientOpPromise::CreateAndReject(rv, __func__);
-    return ref.forget();
-  }
+  RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo();
 
   loadInfo->SetTriggeringPrincipal(principal);
   loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
-  loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
+  loadInfo->SetLoadType(LOAD_STOP_CONTENT);
   loadInfo->SetSourceDocShell(docShell);
   rv = docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
   if (NS_FAILED(rv)) {
     ref = ClientOpPromise::CreateAndReject(rv, __func__);
     return ref.forget();
   }
 
   RefPtr<ClientOpPromise::Private> promise =
--- a/dom/commandhandler/nsCommandParams.h
+++ b/dom/commandhandler/nsCommandParams.h
@@ -37,16 +37,17 @@ protected:
       nsCString* mCString;
     } mData;
 
     nsCOMPtr<nsISupports> mISupports;
 
     HashEntry(uint8_t aType, const char* aEntryName)
       : mEntryName(aEntryName)
       , mEntryType(aType)
+      , mData()
     {
       Reset(mEntryType);
     }
 
     HashEntry(const HashEntry& aRHS)
       : mEntryType(aRHS.mEntryType)
     {
       Reset(mEntryType);
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -334,16 +334,17 @@ FetchDriver::FetchDriver(InternalRequest
                          bool aIsTrackingFetch)
   : mPrincipal(aPrincipal)
   , mLoadGroup(aLoadGroup)
   , mRequest(aRequest)
   , mMainThreadEventTarget(aMainThreadEventTarget)
   , mPerformanceStorage(aPerformanceStorage)
   , mNeedToObserveOnDataAvailable(false)
   , mIsTrackingFetch(aIsTrackingFetch)
+  , mOnStopRequestCalled(false)
 #ifdef DEBUG
   , mResponseAvailableCalled(false)
   , mFetchCalled(false)
 #endif
 {
   AssertIsOnMainThread();
 
   MOZ_ASSERT(aRequest);
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -119,16 +119,17 @@ InternalRequest::InternalRequest(const n
                                  RequestRedirect aRequestRedirect,
                                  RequestCredentials aRequestCredentials,
                                  const nsAString& aReferrer,
                                  ReferrerPolicy aReferrerPolicy,
                                  nsContentPolicyType aContentPolicyType,
                                  const nsAString& aIntegrity)
   : mMethod(aMethod)
   , mHeaders(aHeaders)
+  , mBodyLength(InternalResponse::UNKNOWN_BODY_SIZE)
   , mContentPolicyType(aContentPolicyType)
   , mReferrer(aReferrer)
   , mReferrerPolicy(aReferrerPolicy)
   , mEnvironmentReferrerPolicy(net::RP_Unset)
   , mMode(aMode)
   , mCredentialsMode(aRequestCredentials)
   , mResponseTainting(LoadTainting::Basic)
   , mCacheMode(aCacheMode)
@@ -179,23 +180,26 @@ InternalRequest::InternalRequest(const I
   // NOTE: does not copy body stream... use the fallible Clone() for that
 }
 
 InternalRequest::InternalRequest(const IPCInternalRequest& aIPCRequest)
   : mMethod(aIPCRequest.method())
   , mURLList(aIPCRequest.urls())
   , mHeaders(new InternalHeaders(aIPCRequest.headers(),
                                  aIPCRequest.headersGuard()))
+  , mBodyLength(InternalResponse::UNKNOWN_BODY_SIZE)
   , mContentPolicyType(aIPCRequest.contentPolicyType())
   , mReferrer(aIPCRequest.referrer())
   , mReferrerPolicy(aIPCRequest.referrerPolicy())
+  , mEnvironmentReferrerPolicy(net::RP_Unset)
   , mMode(aIPCRequest.mode())
   , mCredentialsMode(aIPCRequest.credentials())
   , mCacheMode(aIPCRequest.requestCache())
   , mRedirectMode(aIPCRequest.requestRedirect())
+  , mMozErrors(false)
 {
   MOZ_ASSERT(!mURLList.IsEmpty());
 }
 
 InternalRequest::~InternalRequest()
 {
 }
 
--- a/dom/gamepad/GamepadHapticActuator.h
+++ b/dom/gamepad/GamepadHapticActuator.h
@@ -17,20 +17,16 @@ namespace dom {
 class Promise;
 
 class GamepadHapticActuator : public nsISupports,
                               public nsWrapperCache
 {
 public:
   GamepadHapticActuator(nsISupports* aParent, uint32_t aGamepadId,
                         uint32_t aIndex);
-  explicit GamepadHapticActuator(nsISupports* aParent)
-    : mParent(aParent), mType(GamepadHapticActuatorType::Vibration)
-  {
-  }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GamepadHapticActuator)
 
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
--- a/dom/grid/GridLine.cpp
+++ b/dom/grid/GridLine.cpp
@@ -21,16 +21,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 GridLine::GridLine(GridLines *aParent)
   : mParent(aParent)
   , mStart(0.0)
   , mBreadth(0.0)
   , mType(GridDeclaration::Implicit)
   , mNumber(0)
+  , mNegativeNumber(0)
 {
   MOZ_ASSERT(aParent, "Should never be instantiated with a null GridLines");
 }
 
 GridLine::~GridLine()
 {
 }
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -770,18 +770,18 @@ bool
 IndexedDatabaseManager::ExperimentalFeaturesEnabled(JSContext* aCx, JSObject* aGlobal)
 {
   // If, in the child process, properties of the global object are enumerated
   // before the chrome registry (and thus the value of |intl.accept_languages|)
   // is ready, calling IndexedDatabaseManager::Init will permanently break
   // that preference. We can retrieve gExperimentalFeaturesEnabled without
   // actually going through IndexedDatabaseManager.
   // See Bug 1198093 comment 14 for detailed explanation.
-  if (IsNonExposedGlobal(aCx, js::GetGlobalForObjectCrossCompartment(aGlobal),
-                         GlobalNames::BackstagePass)) {
+  MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal));
+  if (IsNonExposedGlobal(aCx, aGlobal, GlobalNames::BackstagePass)) {
     MOZ_ASSERT(NS_IsMainThread());
     static bool featureRetrieved = false;
     if (!featureRetrieved) {
       gExperimentalFeaturesEnabled = Preferences::GetBool(kPrefExperimental);
       featureRetrieved = true;
     }
     return gExperimentalFeaturesEnabled;
   }
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -18,17 +18,18 @@ using namespace mozilla::jsipc;
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(ContentBridgeParent,
                   nsIContentParent,
                   nsIObserver)
 
 ContentBridgeParent::ContentBridgeParent()
-  : mIsForJSPlugin(false)
+  : mIsForBrowser(false)
+  , mIsForJSPlugin(false)
 {}
 
 ContentBridgeParent::~ContentBridgeParent()
 {
 }
 
 void
 ContentBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -109,17 +109,17 @@
 #include "mozilla/Sandbox.h"
 #endif
 #endif
 
 #include "mozilla/Unused.h"
 
 #include "mozInlineSpellChecker.h"
 #include "nsDocShell.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 #include "nsIConsoleListener.h"
 #include "nsIContentViewer.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIIdlePeriod.h"
 #include "nsIDragService.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMemoryInfoDumper.h"
@@ -541,16 +541,17 @@ ContentChild* ContentChild::sSingleton;
 StaticAutoPtr<ContentChild::ShutdownCanary> ContentChild::sShutdownCanary;
 
 ContentChild::ContentChild()
  : mID(uint64_t(-1))
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
  , mMainChromeTid(0)
  , mMsaaID(0)
 #endif
+ , mIsForBrowser(false)
  , mIsAlive(true)
  , mShuttingDown(false)
 {
   // This process is a content process, so it's clearly running in
   // multiprocess mode!
   nsDebugImpl::SetMultiprocessMode("Child");
 
   // When ContentChild is created, the observer service does not even exist.
@@ -751,29 +752,29 @@ ContentChild::ProvideWindow(mozIDOMWindo
                             uint32_t aChromeFlags,
                             bool aCalledFromJS,
                             bool aPositionSpecified,
                             bool aSizeSpecified,
                             nsIURI* aURI,
                             const nsAString& aName,
                             const nsACString& aFeatures,
                             bool aForceNoOpener,
-                            nsIDocShellLoadInfo* aLoadInfo,
+                            nsDocShellLoadInfo* aLoadInfo,
                             bool* aWindowIsNew,
                             mozIDOMWindowProxy** aReturn)
 {
   return ProvideWindowCommon(nullptr, aParent, false, aChromeFlags,
                              aCalledFromJS, aPositionSpecified,
                              aSizeSpecified, aURI, aName, aFeatures,
                              aForceNoOpener, aLoadInfo, aWindowIsNew, aReturn);
 }
 
 static nsresult
 GetCreateWindowParams(mozIDOMWindowProxy* aParent,
-                      nsIDocShellLoadInfo* aLoadInfo,
+                      nsDocShellLoadInfo* aLoadInfo,
                       nsACString& aBaseURIString, float* aFullZoom,
                       uint32_t* aReferrerPolicy,
                       nsIPrincipal** aTriggeringPrincipal)
 {
   *aFullZoom = 1.0f;
   if (!aTriggeringPrincipal) {
     NS_ERROR("aTriggeringPrincipal is null");
     return NS_ERROR_FAILURE;
@@ -791,23 +792,21 @@ GetCreateWindowParams(mozIDOMWindowProxy
   nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
   if (!baseURI) {
     NS_ERROR("nsIDocument didn't return a base URI");
     return NS_ERROR_FAILURE;
   }
 
   baseURI->GetSpec(aBaseURIString);
 
-  bool sendReferrer = true;
   if (aLoadInfo) {
-    aLoadInfo->GetSendReferrer(&sendReferrer);
-    if (!sendReferrer) {
+    if (!aLoadInfo->SendReferrer()) {
       *aReferrerPolicy = mozilla::net::RP_No_Referrer;
     } else {
-      aLoadInfo->GetReferrerPolicy(aReferrerPolicy);
+      *aReferrerPolicy = aLoadInfo->ReferrerPolicy();
     }
   }
 
   RefPtr<nsDocShell> openerDocShell =
     static_cast<nsDocShell*>(opener->GetDocShell());
   if (!openerDocShell) {
     return NS_OK;
   }
@@ -828,17 +827,17 @@ ContentChild::ProvideWindowCommon(TabChi
                                   uint32_t aChromeFlags,
                                   bool aCalledFromJS,
                                   bool aPositionSpecified,
                                   bool aSizeSpecified,
                                   nsIURI* aURI,
                                   const nsAString& aName,
                                   const nsACString& aFeatures,
                                   bool aForceNoOpener,
-                                  nsIDocShellLoadInfo* aLoadInfo,
+                                  nsDocShellLoadInfo* aLoadInfo,
                                   bool* aWindowIsNew,
                                   mozIDOMWindowProxy** aReturn)
 {
   *aReturn = nullptr;
 
   nsAutoPtr<IPCTabContext> ipcContext;
   TabId openerTabId = TabId(0);
   nsAutoCString features(aFeatures);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -29,17 +29,17 @@
 
 struct ChromePackage;
 class nsIObserver;
 struct SubstitutionMapping;
 struct OverrideMapping;
 class nsIDomainPolicy;
 class nsIURIClassifierCallback;
 struct LookAndFeelInt;
-class nsIDocShellLoadInfo;
+class nsDocShellLoadInfo;
 
 namespace mozilla {
 class RemoteSpellcheckEngineChild;
 class ChildProfilerController;
 
 using mozilla::loader::PScriptCacheChild;
 
 #if !defined(XP_WIN)
@@ -110,17 +110,17 @@ public:
                       uint32_t aChromeFlags,
                       bool aCalledFromJS,
                       bool aPositionSpecified,
                       bool aSizeSpecified,
                       nsIURI* aURI,
                       const nsAString& aName,
                       const nsACString& aFeatures,
                       bool aForceNoOpener,
-                      nsIDocShellLoadInfo* aLoadInfo,
+                      nsDocShellLoadInfo* aLoadInfo,
                       bool* aWindowIsNew,
                       mozIDOMWindowProxy** aReturn);
 
   bool Init(MessageLoop* aIOLoop,
             base::ProcessId aParentPid,
             const char* aParentBuildID,
             IPC::Channel* aChannel,
             uint64_t aChildID,
--- a/dom/ipc/FilePickerParent.h
+++ b/dom/ipc/FilePickerParent.h
@@ -21,16 +21,17 @@ namespace dom {
 
 class FilePickerParent : public PFilePickerParent
 {
  public:
   FilePickerParent(const nsString& aTitle,
                    const int16_t& aMode)
   : mTitle(aTitle)
   , mMode(aMode)
+  , mResult(nsIFilePicker::returnOK)
   {}
 
   virtual ~FilePickerParent();
 
   void Done(int16_t aResult);
 
   struct BlobImplOrString
   {
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -118,17 +118,17 @@
 #include "nsICommandParams.h"
 #include "nsISHistory.h"
 #include "nsQueryObject.h"
 #include "nsIHttpChannel.h"
 #include "mozilla/dom/DocGroup.h"
 #include "nsString.h"
 #include "nsISupportsPrimitives.h"
 #include "mozilla/Telemetry.h"
-#include "nsIDocShellLoadInfo.h"
+#include "nsDocShellLoadInfo.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginWidgetChild.h"
 #endif
 
 #ifdef NS_PRINTING
 #include "nsIPrintSession.h"
 #include "nsIPrintSettings.h"
@@ -995,17 +995,17 @@ TabChild::GetInterface(const nsIID & aII
 
 NS_IMETHODIMP
 TabChild::ProvideWindow(mozIDOMWindowProxy* aParent,
                         uint32_t aChromeFlags,
                         bool aCalledFromJS,
                         bool aPositionSpecified, bool aSizeSpecified,
                         nsIURI* aURI, const nsAString& aName,
                         const nsACString& aFeatures, bool aForceNoOpener,
-                        nsIDocShellLoadInfo* aLoadInfo, bool* aWindowIsNew,
+                        nsDocShellLoadInfo* aLoadInfo, bool* aWindowIsNew,
                         mozIDOMWindowProxy** aReturn)
 {
     *aReturn = nullptr;
 
     // If aParent is inside an <iframe mozbrowser> and this isn't a request to
     // open a modal-type window, we're going to create a new <iframe mozbrowser>
     // and return its window here.
     nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -827,17 +827,16 @@ private:
   nsCOMPtr<nsIURI> mLastURI;
   RenderFrameChild* mRemoteFrame;
   RefPtr<nsIContentChild> mManager;
   uint32_t mChromeFlags;
   uint32_t mMaxTouchPoints;
   layers::LayersId mLayersId;
   int64_t mBeforeUnloadListeners;
   CSSRect mUnscaledOuterRect;
-  nscolor mLastBackgroundColor;
   Maybe<bool> mLayersConnected;
   bool mDidFakeShow;
   bool mNotified;
   bool mTriedBrowserInit;
   ScreenOrientationInternal mOrientation;
 
   bool mIgnoreKeyPressEvent;
   RefPtr<APZEventState> mAPZEventState;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -156,16 +156,18 @@ TabParent::TabParent(nsIContentParent* a
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mChromeFlags(aChromeFlags)
   , mDragValid(false)
   , mInitedByParent(false)
   , mTabId(aTabId)
   , mCreatingWindow(false)
   , mCursor(eCursorInvalid)
+  , mCustomCursorHotspotX(0)
+  , mCustomCursorHotspotY(0)
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch(1)
   , mPreserveLayers(false)
   , mRenderLayers(true)
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -191,18 +191,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessagePort)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
 
-MessagePort::MessagePort(nsIGlobalObject* aGlobal)
+MessagePort::MessagePort(nsIGlobalObject* aGlobal, State aState)
   : DOMEventTargetHelper(aGlobal)
+  , mState(aState)
   , mMessageQueueEnabled(false)
   , mIsKeptAlive(false)
   , mHasBeenTransferredOrClosed(false)
 {
   MOZ_ASSERT(aGlobal);
 
   mIdentifier = new MessagePortIdentifier();
   mIdentifier->neutered() = true;
@@ -216,58 +217,55 @@ MessagePort::~MessagePort()
 }
 
 /* static */ already_AddRefed<MessagePort>
 MessagePort::Create(nsIGlobalObject* aGlobal, const nsID& aUUID,
                     const nsID& aDestinationUUID, ErrorResult& aRv)
 {
   MOZ_ASSERT(aGlobal);
 
-  RefPtr<MessagePort> mp = new MessagePort(aGlobal);
+  RefPtr<MessagePort> mp = new MessagePort(aGlobal, eStateUnshippedEntangled);
   mp->Initialize(aUUID, aDestinationUUID, 1 /* 0 is an invalid sequence ID */,
-                 false /* Neutered */, eStateUnshippedEntangled, aRv);
+                 false /* Neutered */, aRv);
   return mp.forget();
 }
 
 /* static */ already_AddRefed<MessagePort>
 MessagePort::Create(nsIGlobalObject* aGlobal,
                     const MessagePortIdentifier& aIdentifier,
                     ErrorResult& aRv)
 {
   MOZ_ASSERT(aGlobal);
 
-  RefPtr<MessagePort> mp = new MessagePort(aGlobal);
+  RefPtr<MessagePort> mp = new MessagePort(aGlobal, eStateEntangling);
   mp->Initialize(aIdentifier.uuid(), aIdentifier.destinationUuid(),
-                 aIdentifier.sequenceId(), aIdentifier.neutered(),
-                 eStateEntangling, aRv);
+                 aIdentifier.sequenceId(), aIdentifier.neutered(), aRv);
   return mp.forget();
 }
 
 void
 MessagePort::UnshippedEntangle(MessagePort* aEntangledPort)
 {
   MOZ_ASSERT(aEntangledPort);
   MOZ_ASSERT(!mUnshippedEntangledPort);
 
   mUnshippedEntangledPort = aEntangledPort;
 }
 
 void
 MessagePort::Initialize(const nsID& aUUID,
                         const nsID& aDestinationUUID,
                         uint32_t aSequenceID, bool mNeutered,
-                        State aState, ErrorResult& aRv)
+                        ErrorResult& aRv)
 {
   MOZ_ASSERT(mIdentifier);
   mIdentifier->uuid() = aUUID;
   mIdentifier->destinationUuid() = aDestinationUUID;
   mIdentifier->sequenceId() = aSequenceID;
 
-  mState = aState;
-
   if (mNeutered) {
     // If this port is neutered we don't want to keep it alive artificially nor
     // we want to add listeners or WorkerRefs.
     mState = eStateDisentangled;
     return;
   }
 
   if (mState == eStateEntangling) {
--- a/dom/messagechannel/MessagePort.h
+++ b/dom/messagechannel/MessagePort.h
@@ -84,21 +84,16 @@ public:
   // These methods are useful for MessagePortChild
 
   void Entangled(nsTArray<ClonedMessageData>& aMessages);
   void MessagesReceived(nsTArray<ClonedMessageData>& aMessages);
   void StopSendingDataConfirmed();
   void Closed();
 
 private:
-  explicit MessagePort(nsIGlobalObject* aGlobal);
-  ~MessagePort();
-
-  void DisconnectFromOwner() override;
-
   enum State {
     // When a port is created by a MessageChannel it is entangled with the
     // other. They both run on the same thread, same event loop and the
     // messages are added to the queues without using PBackground actors.
     // When one of the port is shipped, the state is changed to
     // StateEntangling.
     eStateUnshippedEntangled,
 
@@ -134,19 +129,23 @@ private:
     // though the actor.
     eStateDisentangled,
 
     // We are here if Close() has been called. We are disentangled but we can
     // still send pending messages.
     eStateDisentangledForClose
   };
 
+  explicit MessagePort(nsIGlobalObject* aGlobal, State aState);
+  ~MessagePort();
+
+  void DisconnectFromOwner() override;
+
   void Initialize(const nsID& aUUID, const nsID& aDestinationUUID,
-                  uint32_t aSequenceID, bool mNeutered, State aState,
-                  ErrorResult& aRv);
+                  uint32_t aSequenceID, bool mNeutered, ErrorResult& aRv);
 
   bool ConnectToPBackground();
 
   // Dispatch events from the Message Queue using a nsRunnable.
   void Dispatch();
 
   void DispatchError();
 
--- a/dom/payments/PaymentActionResponse.cpp
+++ b/dom/payments/PaymentActionResponse.cpp
@@ -148,16 +148,17 @@ PaymentActionResponse::GetType(uint32_t*
 
 /* PaymentCanMakeActionResponse */
 
 NS_IMPL_ISUPPORTS_INHERITED(PaymentCanMakeActionResponse,
                             PaymentActionResponse,
                             nsIPaymentCanMakeActionResponse)
 
 PaymentCanMakeActionResponse::PaymentCanMakeActionResponse()
+  : mResult(false)
 {
   mType = nsIPaymentActionResponse::CANMAKE_ACTION;
 }
 
 NS_IMETHODIMP
 PaymentCanMakeActionResponse::GetResult(bool* aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
@@ -175,16 +176,17 @@ PaymentCanMakeActionResponse::Init(const
 
 /* PaymentShowActionResponse */
 
 NS_IMPL_ISUPPORTS_INHERITED(PaymentShowActionResponse,
                             PaymentActionResponse,
                             nsIPaymentShowActionResponse)
 
 PaymentShowActionResponse::PaymentShowActionResponse()
+  : mAcceptStatus(nsIPaymentActionResponse::PAYMENT_REJECTED)
 {
   mType = nsIPaymentActionResponse::SHOW_ACTION;
 }
 
 NS_IMETHODIMP
 PaymentShowActionResponse::GetAcceptStatus(uint32_t* aAcceptStatus)
 {
   NS_ENSURE_ARG_POINTER(aAcceptStatus);
@@ -286,16 +288,17 @@ PaymentShowActionResponse::Init(const ns
 
 /* PaymentAbortActionResponse */
 
 NS_IMPL_ISUPPORTS_INHERITED(PaymentAbortActionResponse,
                             PaymentActionResponse,
                             nsIPaymentAbortActionResponse)
 
 PaymentAbortActionResponse::PaymentAbortActionResponse()
+  : mAbortStatus(nsIPaymentActionResponse::ABORT_FAILED)
 {
   mType = nsIPaymentActionResponse::ABORT_ACTION;
 }
 
 NS_IMETHODIMP
 PaymentAbortActionResponse::GetAbortStatus(uint32_t* aAbortStatus)
 {
   NS_ENSURE_ARG_POINTER(aAbortStatus);
@@ -322,16 +325,17 @@ PaymentAbortActionResponse::IsSucceeded(
 
 /* PaymentCompleteActionResponse */
 
 NS_IMPL_ISUPPORTS_INHERITED(PaymentCompleteActionResponse,
                             PaymentActionResponse,
                             nsIPaymentCompleteActionResponse)
 
 PaymentCompleteActionResponse::PaymentCompleteActionResponse()
+  : mCompleteStatus(nsIPaymentActionResponse::COMPLETE_FAILED)
 {
   mType = nsIPaymentActionResponse::COMPLETE_ACTION;
 }
 
 nsresult
 PaymentCompleteActionResponse::Init(const nsAString& aRequestId,
                                     const uint32_t aCompleteStatus)
 {
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -51,43 +51,46 @@ NS_IMPL_RELEASE_INHERITED(Performance, D
 Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
                                  nsIPrincipal* aPrincipal,
                                  nsDOMNavigationTiming* aDOMTiming,
                                  nsITimedChannel* aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<Performance> performance =
-    new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
-  performance->mSystemPrincipal = nsContentUtils::IsSystemPrincipal(aPrincipal);
+    new PerformanceMainThread(aWindow,
+                              aDOMTiming,
+                              aChannel,
+                              nsContentUtils::IsSystemPrincipal(aPrincipal));
   return performance.forget();
 }
 
 /* static */ already_AddRefed<Performance>
 Performance::CreateForWorker(WorkerPrivate* aWorkerPrivate)
 {
   MOZ_ASSERT(aWorkerPrivate);
   aWorkerPrivate->AssertIsOnWorkerThread();
 
   RefPtr<Performance> performance = new PerformanceWorker(aWorkerPrivate);
-  performance->mSystemPrincipal = aWorkerPrivate->UsesSystemPrincipal();
   return performance.forget();
 }
 
-Performance::Performance()
+Performance::Performance(bool aSystemPrincipal)
   : mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
   , mPendingNotificationObserversTask(false)
+  , mSystemPrincipal(aSystemPrincipal)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 }
 
-Performance::Performance(nsPIDOMWindowInner* aWindow)
+Performance::Performance(nsPIDOMWindowInner* aWindow, bool aSystemPrincipal)
   : DOMEventTargetHelper(aWindow)
   , mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
   , mPendingNotificationObserversTask(false)
+  , mSystemPrincipal(aSystemPrincipal)
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 Performance::~Performance()
 {}
 
 DOMHighResTimeStamp
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -113,18 +113,18 @@ public:
   void MemoryPressure();
 
   size_t SizeOfUserEntries(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfResourceEntries(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   void InsertResourceEntry(PerformanceEntry* aEntry);
 
 protected:
-  Performance();
-  explicit Performance(nsPIDOMWindowInner* aWindow);
+  explicit Performance(bool aSystemPrincipal);
+  Performance(nsPIDOMWindowInner* aWindow, bool aSystemPrincipal);
 
   virtual ~Performance();
 
   virtual void InsertUserEntry(PerformanceEntry* aEntry);
 
   void ClearUserEntries(const Optional<nsAString>& aEntryName,
                         const nsAString& aEntryType);
 
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -70,18 +70,19 @@ NS_IMPL_RELEASE_INHERITED(PerformanceMai
 // QueryInterface implementation for PerformanceMainThread
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMainThread)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END_INHERITING(Performance)
 
 PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
                                              nsDOMNavigationTiming* aDOMTiming,
-                                             nsITimedChannel* aChannel)
-  : Performance(aWindow)
+                                             nsITimedChannel* aChannel,
+                                             bool aPrincipal)
+  : Performance(aWindow, aPrincipal)
   , mDOMTiming(aDOMTiming)
   , mChannel(aChannel)
 {
   MOZ_ASSERT(aWindow, "Parent window object should be provided");
 }
 
 PerformanceMainThread::~PerformanceMainThread()
 {
--- a/dom/performance/PerformanceMainThread.h
+++ b/dom/performance/PerformanceMainThread.h
@@ -14,17 +14,18 @@ namespace mozilla {
 namespace dom {
 
 class PerformanceMainThread final : public Performance
                                   , public PerformanceStorage
 {
 public:
   PerformanceMainThread(nsPIDOMWindowInner* aWindow,
                         nsDOMNavigationTiming* aDOMTiming,
-                        nsITimedChannel* aChannel);
+                        nsITimedChannel* aChannel,
+                        bool aPrincipal);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMainThread,
                                                          Performance)
 
   PerformanceStorage* AsPerformanceStorage() override
   {
     return this;
--- a/dom/performance/PerformanceWorker.cpp
+++ b/dom/performance/PerformanceWorker.cpp
@@ -7,17 +7,18 @@
 #include "PerformanceWorker.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/WorkerPrivate.h"
 
 namespace mozilla {
 namespace dom {
 
 PerformanceWorker::PerformanceWorker(WorkerPrivate* aWorkerPrivate)
-  : mWorkerPrivate(aWorkerPrivate)
+  : Performance(aWorkerPrivate->UsesSystemPrincipal())
+  , mWorkerPrivate(aWorkerPrivate)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 }
 
 PerformanceWorker::~PerformanceWorker()
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 }
--- a/dom/script/ScriptSettings.cpp
+++ b/dom/script/ScriptSettings.cpp
@@ -563,25 +563,26 @@ AutoJSAPI::ReportException()
   JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
   if (!errorGlobal) {
     if (mIsMainThread) {
       errorGlobal = xpc::PrivilegedJunkScope();
     } else {
       errorGlobal = GetCurrentThreadWorkerGlobal();
     }
   }
+  MOZ_ASSERT(JS_IsGlobalObject(errorGlobal));
   JSAutoRealm ar(cx(), errorGlobal);
   JS::Rooted<JS::Value> exn(cx());
   js::ErrorReport jsReport(cx());
   if (StealException(&exn) &&
       jsReport.init(cx(), exn, js::ErrorReport::WithSideEffects)) {
     if (mIsMainThread) {
       RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
 
-      RefPtr<nsGlobalWindowInner> win = xpc::WindowGlobalOrNull(errorGlobal);
+      RefPtr<nsGlobalWindowInner> win = xpc::WindowOrNull(errorGlobal);
       nsPIDOMWindowInner* inner = win ? win->AsInner() : nullptr;
       bool isChrome = nsContentUtils::IsSystemPrincipal(
         nsContentUtils::ObjectPrincipal(errorGlobal));
       xpcReport->Init(jsReport.report(), jsReport.toStringResult().c_str(),
                       isChrome,
                       inner ? inner->WindowID() : 0);
       if (inner && jsReport.report()->errorNumber != JSMSG_OUT_OF_MEMORY) {
         JS::RootingContext* rcx = JS::RootingContext::get(cx());
--- a/dom/serviceworkers/ServiceWorkerUpdateJob.cpp
+++ b/dom/serviceworkers/ServiceWorkerUpdateJob.cpp
@@ -203,16 +203,17 @@ ServiceWorkerUpdateJob::ServiceWorkerUpd
     nsIPrincipal* aPrincipal,
     const nsACString& aScope,
     const nsACString& aScriptSpec,
     nsILoadGroup* aLoadGroup,
     ServiceWorkerUpdateViaCache aUpdateViaCache)
   : ServiceWorkerJob(aType, aPrincipal, aScope, aScriptSpec)
   , mLoadGroup(aLoadGroup)
   , mUpdateViaCache(aUpdateViaCache)
+  , mOnFailure(serviceWorkerScriptCache::OnFailure::DoNothing)
 {
 }
 
 ServiceWorkerUpdateJob::~ServiceWorkerUpdateJob()
 {
 }
 
 void
--- a/dom/storage/StorageIPC.cpp
+++ b/dom/storage/StorageIPC.cpp
@@ -912,16 +912,17 @@ public:
                const nsAString& aValue = EmptyString())
     : Runnable("dom::LoadRunnable")
     , mParent(aParent)
     , mType(aType)
     , mSuffix(aOriginSuffix)
     , mOrigin(aOriginNoSuffix)
     , mKey(aKey)
     , mValue(aValue)
+    , mRv(NS_ERROR_NOT_INITIALIZED)
   { }
 
   LoadRunnable(StorageDBParent* aParent,
                TaskType aType,
                const nsACString& aOriginSuffix,
                const nsACString& aOriginNoSuffix,
                nsresult aRv)
     : Runnable("dom::LoadRunnable")
--- a/dom/websocket/WebSocket.cpp
+++ b/dom/websocket/WebSocket.cpp
@@ -93,16 +93,17 @@ public:
   : mWebSocket(aWebSocket)
   , mIsServerSide(false)
   , mSecure(false)
   , mOnCloseScheduled(false)
   , mFailed(false)
   , mDisconnectingOrDisconnected(false)
   , mCloseEventWasClean(false)
   , mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL)
+  , mPort(0)
   , mScriptLine(0)
   , mScriptColumn(0)
   , mInnerWindowID(0)
   , mPrivateBrowsing(false)
   , mIsMainThread(true)
   , mMutex("WebSocketImpl::mMutex")
   , mWorkerShuttingDown(false)
   {
--- a/dom/worklet/Worklet.cpp
+++ b/dom/worklet/Worklet.cpp
@@ -428,19 +428,29 @@ ExecutionRunnable::RunOnMainThread()
   }
 
   mHandler->ExecutionSucceeded();
 }
 
 // ---------------------------------------------------------------------------
 // WorkletLoadInfo
 
-WorkletLoadInfo::WorkletLoadInfo()
+WorkletLoadInfo::WorkletLoadInfo(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal)
+  : mInnerWindowID(aWindow->WindowID())
+  , mDumpEnabled(DOMPrefs::DumpEnabled())
+  , mOriginAttributes(BasePrincipal::Cast(aPrincipal)->OriginAttributesRef())
+  , mPrincipal(aPrincipal)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  nsPIDOMWindowOuter* outerWindow = aWindow->GetOuterWindow();
+  if (outerWindow) {
+    mOuterWindowID = outerWindow->WindowID();
+  } else {
+    mOuterWindowID = 0;
+  }
 }
 
 WorkletLoadInfo::~WorkletLoadInfo()
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 // ---------------------------------------------------------------------------
@@ -467,42 +477,25 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 Worklet::Worklet(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
                  WorkletType aWorkletType)
   : mWindow(aWindow)
   , mWorkletType(aWorkletType)
+  , mWorkletLoadInfo(aWindow, aPrincipal)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(NS_IsMainThread());
 
 #ifdef RELEASE_OR_BETA
   MOZ_CRASH("This code should not go to release/beta yet!");
 #endif
-
-  // Reset mWorkletLoadInfo and populate it.
-
-  memset(&mWorkletLoadInfo, 0, sizeof(WorkletLoadInfo));
-
-  mWorkletLoadInfo.mInnerWindowID = aWindow->WindowID();
-
-  nsPIDOMWindowOuter* outerWindow = aWindow->GetOuterWindow();
-  if (outerWindow) {
-    mWorkletLoadInfo.mOuterWindowID = outerWindow->WindowID();
-  }
-
-  mWorkletLoadInfo.mOriginAttributes =
-    BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
-
-  mWorkletLoadInfo.mPrincipal = aPrincipal;
-
-  mWorkletLoadInfo.mDumpEnabled = DOMPrefs::DumpEnabled();
 }
 
 Worklet::~Worklet()
 {
   TerminateThread();
 }
 
 JSObject*
--- a/dom/worklet/Worklet.h
+++ b/dom/worklet/Worklet.h
@@ -25,17 +25,17 @@ class Worklet;
 class WorkletFetchHandler;
 class WorkletGlobalScope;
 class WorkletThread;
 enum class CallerType : uint32_t;
 
 class WorkletLoadInfo
 {
 public:
-  WorkletLoadInfo();
+  WorkletLoadInfo(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal);
   ~WorkletLoadInfo();
 
   uint64_t OuterWindowID() const { return mOuterWindowID; }
   uint64_t InnerWindowID() const { return mInnerWindowID; }
   bool DumpEnabled() const { return mDumpEnabled; }
 
   const OriginAttributes& OriginAttributesRef() const
   {
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -205,16 +205,17 @@ XMLHttpRequestMainThread::XMLHttpRequest
     mProgressSinceLastProgressEvent(false),
     mRequestSentTime(0), mTimeoutMilliseconds(0),
     mErrorLoad(ErrorType::eOK), mErrorParsingXML(false),
     mWaitingForOnStopRequest(false),
     mProgressTimerIsActive(false),
     mIsHtml(false),
     mWarnAboutSyncHtml(false),
     mLoadTotal(-1),
+    mLoadTransferred(0),
     mIsSystem(false),
     mIsAnon(false),
     mFirstStartRequestSeen(false),
     mInLoadProgressEvent(false),
     mResultJSON(JS::UndefinedValue()),
     mResultArrayBuffer(nullptr),
     mIsMappedArrayBuffer(false),
     mXPCOMifier(nullptr),
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -594,26 +594,26 @@ public:
    * be used to determine if the memory needs to be cleared to 0.
    */
   virtual bool OnHeap() const
   {
     return true;
   }
 
   /**
-   * Indicates how many times the surface has been invalidated.
+   * Yields a dirty rect of what has changed since it was last called.
    */
-  virtual int32_t Invalidations() const {
-    return -1;
+  virtual Maybe<IntRect> TakeDirtyRect() {
+    return Nothing();
   }
 
   /**
-   * Increment the invalidation counter.
+   * Indicate a region which has changed in the surface.
    */
-  virtual void Invalidate() { }
+  virtual void Invalidate(const IntRect& aDirtyRect) { }
 
 protected:
   bool mIsMapped;
 };
 
 /** This is an abstract object that accepts path segments. */
 class PathSink : public RefCounted<PathSink>
 {
--- a/gfx/layers/SourceSurfaceSharedData.h
+++ b/gfx/layers/SourceSurfaceSharedData.h
@@ -114,17 +114,16 @@ class SourceSurfaceSharedData final : pu
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)
 
   SourceSurfaceSharedData()
     : mMutex("SourceSurfaceSharedData")
     , mStride(0)
     , mMapCount(0)
     , mHandleCount(0)
-    , mInvalidations(0)
     , mFormat(SurfaceFormat::UNKNOWN)
     , mClosed(false)
     , mFinalized(false)
     , mShared(false)
   {
   }
 
   /**
@@ -244,32 +243,44 @@ public:
    */
   bool IsFinalized() const
   {
     MutexAutoLock lock(mMutex);
     return mFinalized;
   }
 
   /**
-   * Indicates how many times the surface has been invalidated.
+   * Yields a dirty rect of what has changed since it was last called.
    */
-  int32_t Invalidations() const override
+  Maybe<IntRect> TakeDirtyRect() override
   {
     MutexAutoLock lock(mMutex);
-    return mInvalidations;
+    if (mDirtyRect) {
+      Maybe<IntRect> ret = std::move(mDirtyRect);
+      return ret;
+    }
+    return Nothing();
   }
 
   /**
    * Increment the invalidation counter.
    */
-  void Invalidate() override
+  void Invalidate(const IntRect& aDirtyRect) override
   {
     MutexAutoLock lock(mMutex);
-    ++mInvalidations;
-    MOZ_ASSERT(mInvalidations >= 0);
+    if (!aDirtyRect.IsEmpty()) {
+      if (mDirtyRect) {
+        mDirtyRect->UnionRect(mDirtyRect.ref(), aDirtyRect);
+      } else {
+        mDirtyRect = Some(aDirtyRect);
+      }
+    } else {
+      mDirtyRect = Some(IntRect(IntPoint(0, 0), mSize));
+    }
+    MOZ_ASSERT_IF(mDirtyRect, !mDirtyRect->IsEmpty());
   }
 
   /**
    * While a HandleLock exists for the given surface, the shared memory handle
    * cannot be released.
    */
   class MOZ_STACK_CLASS HandleLock final {
   public:
@@ -328,17 +339,17 @@ private:
    * and we have completed sharing will it be released.
    */
   void CloseHandleInternal();
 
   mutable Mutex mMutex;
   int32_t mStride;
   int32_t mMapCount;
   int32_t mHandleCount;
-  int32_t mInvalidations;
+  Maybe<IntRect> mDirtyRect;
   IntSize mSize;
   RefPtr<SharedMemoryBasic> mBuf;
   RefPtr<SharedMemoryBasic> mOldBuf;
   SurfaceFormat mFormat;
   bool mClosed : 1;
   bool mFinalized : 1;
   bool mShared : 1;
 };
--- a/gfx/layers/basic/BasicPaintedLayer.cpp
+++ b/gfx/layers/basic/BasicPaintedLayer.cpp
@@ -85,19 +85,22 @@ BasicPaintedLayer::PaintThebes(gfxContex
             BasicManager()->PushGroupForLayer(aContext, this, toDraw, group);
         if (availableGroup) {
           context = group.mGroupTarget;
         }
       } else {
         context = aContext;
       }
       if (context) {
-        SetAntialiasingFlags(this, context->GetDrawTarget());
+        DrawTarget* target = context->GetDrawTarget();
+        bool oldAA = target->GetPermitSubpixelAA();
+        SetAntialiasingFlags(this, target);
         aCallback(this, context, toDraw, toDraw, DrawRegionClip::NONE,
                   nsIntRegion(), aCallbackData);
+        target->SetPermitSubpixelAA(oldAA);
       }
       if (needsGroup && availableGroup) {
         BasicManager()->PopGroupForLayer(group);
       }
 
       aContext->Restore();
     }
 
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -130,17 +130,17 @@ CompositorBridgeChild::AfterDestroy()
     sCompositorBridge = nullptr;
   }
 }
 
 void
 CompositorBridgeChild::Destroy()
 {
   // This must not be called from the destructor!
-  mTexturesWaitingRecycled.Clear();
+  mTexturesWaitingRecycled.clear();
 
   // Destroying the layer manager may cause all sorts of things to happen, so
   // let's make sure there is still a reference to keep this alive whatever
   // happens.
   RefPtr<CompositorBridgeChild> selfRef = this;
 
   for (size_t i = 0; i < mTexturePools.Length(); i++) {
     mTexturePools[i]->Destroy();
@@ -893,35 +893,36 @@ CompositorBridgeChild::HoldUntilComposit
     return;
   }
 
   if (!(aClient->GetFlags() & TextureFlags::RECYCLE)) {
     return;
   }
 
   aClient->SetLastFwdTransactionId(GetFwdTransactionId());
-  mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
+  mTexturesWaitingRecycled.emplace(aClient->GetSerial(), aClient);
 }
 
 void
 CompositorBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
 {
-  if (auto entry = mTexturesWaitingRecycled.Lookup(aTextureId)) {
-    if (aFwdTransactionId < entry.Data()->GetLastFwdTransactionId()) {
+  auto it = mTexturesWaitingRecycled.find(aTextureId);
+  if (it != mTexturesWaitingRecycled.end()) {
+    if (aFwdTransactionId < it->second->GetLastFwdTransactionId()) {
       // Released on host side, but client already requested newer use texture.
       return;
     }
-    entry.Remove();
+    mTexturesWaitingRecycled.erase(it);
   }
 }
 
 void
 CompositorBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
 {
-  mTexturesWaitingRecycled.Remove(aTextureId);
+  mTexturesWaitingRecycled.erase(aTextureId);
 }
 
 TextureClientPool*
 CompositorBridgeChild::GetTexturePool(KnowsCompositor* aAllocator,
                                       SurfaceFormat aFormat,
                                       TextureFlags aFlags)
 {
   for (size_t i = 0; i < mTexturePools.Length(); i++) {
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -12,23 +12,24 @@
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/Monitor.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/PCompositorBridgeChild.h"
 #include "mozilla/layers/TextureForwarder.h" // for TextureForwarder
 #include "mozilla/layers/PaintThread.h" // for PaintThread
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsClassHashtable.h"           // for nsClassHashtable
-#include "nsRefPtrHashtable.h"
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsHashKeys.h"                 // for nsUint64HashKey
 #include "nsISupportsImpl.h"            // for NS_INLINE_DECL_REFCOUNTING
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 #include "nsWeakReference.h"
 
+#include <unordered_map>
+
 namespace mozilla {
 
 namespace dom {
 class TabChild;
 } // namespace dom
 
 namespace widget {
 class CompositorWidget;
@@ -384,17 +385,17 @@ private:
    * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() call.
    */
   uint64_t mFwdTransactionId;
 
   /**
    * Hold TextureClients refs until end of their usages on host side.
    * It defer calling of TextureClient recycle callback.
    */
-  nsRefPtrHashtable<nsUint64HashKey, TextureClient> mTexturesWaitingRecycled;
+  std::unordered_map<uint64_t, RefPtr<TextureClient>> mTexturesWaitingRecycled;
 
   MessageLoop* mMessageLoop;
 
   AutoTArray<RefPtr<TextureClientPool>,2> mTexturePools;
 
   uint64_t mProcessToken;
 
   FixedSizeSmallShmemSectionAllocator* mSectionAllocator;
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -153,36 +153,37 @@ void
 ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient)
 {
   // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE is set on ImageBridge.
   if (!aClient ||
       !(aClient->GetFlags() & TextureFlags::RECYCLE)) {
     return;
   }
   aClient->SetLastFwdTransactionId(GetFwdTransactionId());
-  mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
+  mTexturesWaitingRecycled.emplace(aClient->GetSerial(), aClient);
 }
 
 void
 ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
 {
-  if (auto entry = mTexturesWaitingRecycled.Lookup(aTextureId)) {
-    if (aFwdTransactionId < entry.Data()->GetLastFwdTransactionId()) {
+  auto it = mTexturesWaitingRecycled.find(aTextureId);
+  if (it != mTexturesWaitingRecycled.end()) {
+    if (aFwdTransactionId < it->second->GetLastFwdTransactionId()) {
       // Released on host side, but client already requested newer use texture.
       return;
     }
-    entry.Remove();
+    mTexturesWaitingRecycled.erase(it);
   }
 }
 
 void
 ImageBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
 {
   MOZ_ASSERT(InImageBridgeChildThread());
-  mTexturesWaitingRecycled.Remove(aTextureId);
+  mTexturesWaitingRecycled.erase(aTextureId);
 }
 
 // Singleton
 static StaticMutex sImageBridgeSingletonLock;
 static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
 static Thread *sImageBridgeChildThread = nullptr;
 
 // dispatched function
@@ -230,17 +231,17 @@ ImageBridgeChild::ShutdownStep2(Synchron
 
 void
 ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mCanSend = false;
   mDestroyed = true;
   {
     MutexAutoLock lock(mContainerMapLock);
-    mImageContainerListeners.Clear();
+    mImageContainerListeners.clear();
   }
 }
 
 void
 ImageBridgeChild::DeallocPImageBridgeChild()
 {
   this->Release();
 }
@@ -282,17 +283,17 @@ ImageBridgeChild::ImageBridgeChild(uint3
 ImageBridgeChild::~ImageBridgeChild()
 {
   delete mTxn;
 }
 
 void
 ImageBridgeChild::MarkShutDown()
 {
-  mTexturesWaitingRecycled.Clear();
+  mTexturesWaitingRecycled.clear();
 
   mCanSend = false;
 }
 
 void
 ImageBridgeChild::Connect(CompositableClient* aCompositable,
                           ImageContainer* aImageContainer)
 {
@@ -305,30 +306,30 @@ ImageBridgeChild::Connect(CompositableCl
   // we don't want old IDs to potentially leak into a recreated ImageBridge.
   static uint64_t sNextID = 1;
   uint64_t id = sNextID++;
 
   // ImageClient of ImageContainer provides aImageContainer.
   // But offscreen canvas does not provide it.
   if (aImageContainer) {
     MutexAutoLock lock(mContainerMapLock);
-    MOZ_ASSERT(!mImageContainerListeners.Contains(id));
-    mImageContainerListeners.Put(id, aImageContainer->GetImageContainerListener());
+    MOZ_ASSERT(mImageContainerListeners.find(id) == mImageContainerListeners.end());
+    mImageContainerListeners.emplace(id, aImageContainer->GetImageContainerListener());
   }
 
   CompositableHandle handle(id);
   aCompositable->InitIPDL(handle);
   SendNewCompositable(handle, aCompositable->GetTextureInfo(), GetCompositorBackendType());
 }
 
 void
 ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle)
 {
   MutexAutoLock lock(mContainerMapLock);
-  mImageContainerListeners.Remove(aHandle.Value());
+  mImageContainerListeners.erase(aHandle.Value());
 }
 
 Thread* ImageBridgeChild::GetThread() const
 {
   return sImageBridgeChildThread;
 }
 
 /* static */ RefPtr<ImageBridgeChild>
@@ -719,19 +720,18 @@ ImageBridgeChild::UpdateTextureFactoryId
   bool needsDrop = disablingWebRender;
 #endif
 
   IdentifyTextureHost(aIdentifier);
   if (needsDrop) {
     nsTArray<RefPtr<ImageContainerListener> > listeners;
     {
       MutexAutoLock lock(mContainerMapLock);
-      for (auto iter = mImageContainerListeners.Iter(); !iter.Done(); iter.Next()) {
-        RefPtr<ImageContainerListener>& listener = iter.Data();
-        listeners.AppendElement(listener);
+      for (const auto& entry : mImageContainerListeners) {
+        listeners.AppendElement(entry.second);
       }
     }
     // Drop ImageContainer's ImageClient whithout holding mContainerMapLock to avoid deadlock.
     for (auto container : listeners) {
       container->DropImageClient();
     }
   }
 }
@@ -999,18 +999,19 @@ ImageBridgeChild::RecvParentAsyncMessage
 
 mozilla::ipc::IPCResult
 ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
 {
   for (auto& n : aNotifications) {
     RefPtr<ImageContainerListener> listener;
     {
       MutexAutoLock lock(mContainerMapLock);
-      if (auto entry = mImageContainerListeners.Lookup(n.compositable().Value())) {
-        listener = entry.Data();
+      auto it = mImageContainerListeners.find(n.compositable().Value());
+      if (it != mImageContainerListeners.end()) {
+        listener = it->second;
       }
     }
     if (listener) {
       listener->NotifyComposite(n);
     }
   }
   return IPC_OK();
 }
@@ -1112,17 +1113,17 @@ ImageBridgeChild::ReleaseCompositable(co
   }
 
   if (!DestroyInTransaction(aHandle)) {
     SendReleaseCompositable(aHandle);
   }
 
   {
     MutexAutoLock lock(mContainerMapLock);
-    mImageContainerListeners.Remove(aHandle.Value());
+    mImageContainerListeners.erase(aHandle.Value());
   }
 }
 
 bool
 ImageBridgeChild::CanSend() const
 {
   MOZ_ASSERT(InImageBridgeChildThread());
   return mCanSend;
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -4,29 +4,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_IMAGEBRIDGECHILD_H
 #define MOZILLA_GFX_IMAGEBRIDGECHILD_H
 
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint64_t
+#include <unordered_map>
+
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/Atomics.h"
 #include "mozilla/RefPtr.h"             // for already_AddRefed
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/CanvasClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/PImageBridgeChild.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsIObserver.h"
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsRefPtrHashtable.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
 
 class MessageLoop;
 
 namespace base {
 class Thread;
 } // namespace base
@@ -390,23 +391,23 @@ private:
    * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() call.
    */
   uint64_t mFwdTransactionId;
 
   /**
    * Hold TextureClients refs until end of their usages on host side.
    * It defer calling of TextureClient recycle callback.
    */
-  nsRefPtrHashtable<nsUint64HashKey, TextureClient> mTexturesWaitingRecycled;
+  std::unordered_map<uint64_t, RefPtr<TextureClient>> mTexturesWaitingRecycled;
 
   /**
    * Mapping from async compositable IDs to image containers.
    */
   Mutex mContainerMapLock;
-  nsRefPtrHashtable<nsUint64HashKey, ImageContainerListener> mImageContainerListeners;
+  std::unordered_map<uint64_t, RefPtr<ImageContainerListener>> mImageContainerListeners;
 
 #if defined(XP_WIN)
   /**
    * Used for checking if D3D11Device is updated.
    */
   RefPtr<ID3D11Device> mImageDevice;
 #endif
 };
--- a/gfx/layers/ipc/SharedSurfacesChild.cpp
+++ b/gfx/layers/ipc/SharedSurfacesChild.cpp
@@ -18,43 +18,38 @@ namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 class SharedSurfacesChild::ImageKeyData final
 {
 public:
   ImageKeyData(WebRenderLayerManager* aManager,
-               const wr::ImageKey& aImageKey,
-               int32_t aInvalidations)
+               const wr::ImageKey& aImageKey)
     : mManager(aManager)
     , mImageKey(aImageKey)
-    , mInvalidations(aInvalidations)
   { }
 
   ImageKeyData(ImageKeyData&& aOther)
     : mManager(std::move(aOther.mManager))
     , mImageKey(aOther.mImageKey)
-    , mInvalidations(aOther.mInvalidations)
   { }
 
   ImageKeyData& operator=(ImageKeyData&& aOther)
   {
     mManager = std::move(aOther.mManager);
     mImageKey = aOther.mImageKey;
-    mInvalidations = aOther.mInvalidations;
     return *this;
   }
 
   ImageKeyData(const ImageKeyData&) = delete;
   ImageKeyData& operator=(const ImageKeyData&) = delete;
 
   RefPtr<WebRenderLayerManager> mManager;
   wr::ImageKey mImageKey;
-  int32_t mInvalidations;
 };
 
 class SharedSurfacesChild::SharedUserData final
 {
 public:
   explicit SharedUserData(const wr::ExternalImageId& aId)
     : mId(aId)
     , mShared(false)
@@ -114,17 +109,17 @@ public:
   void MarkShared()
   {
     MOZ_ASSERT(!mShared);
     mShared = true;
   }
 
   wr::ImageKey UpdateKey(WebRenderLayerManager* aManager,
                          wr::IpcResourceUpdateQueue& aResources,
-                         int32_t aInvalidations)
+                         const Maybe<IntRect>& aDirtyRect)
   {
     MOZ_ASSERT(aManager);
     MOZ_ASSERT(!aManager->IsDestroyed());
 
     // We iterate through all of the items to ensure we clean up the old
     // WebRenderLayerManager references. Most of the time there will be few
     // entries and this should not be particularly expensive compared to the
     // cost of duplicating image keys. In an ideal world, we would generate a
@@ -141,33 +136,32 @@ public:
       } else if (entry.mManager == aManager) {
         WebRenderBridgeChild* wrBridge = aManager->WrBridge();
         MOZ_ASSERT(wrBridge);
 
         // Even if the manager is the same, its underlying WebRenderBridgeChild
         // can change state. If our namespace differs, then our old key has
         // already been discarded.
         bool ownsKey = wrBridge->GetNamespace() == entry.mImageKey.mNamespace;
-        if (!ownsKey || entry.mInvalidations != aInvalidations) {
-          if (ownsKey) {
-            aManager->AddImageKeyForDiscard(entry.mImageKey);
-          }
-          entry.mInvalidations = aInvalidations;
+        if (!ownsKey) {
           entry.mImageKey = wrBridge->GetNextImageKey();
           aResources.AddExternalImage(mId, entry.mImageKey);
+        } else if (aDirtyRect) {
+          aResources.UpdateExternalImage(mId, entry.mImageKey,
+                                         ViewAs<ImagePixel>(aDirtyRect.ref()));
         }
 
         key = entry.mImageKey;
         found = true;
       }
     }
 
     if (!found) {
       key = aManager->WrBridge()->GetNextImageKey();
-      ImageKeyData data(aManager, key, aInvalidations);
+      ImageKeyData data(aManager, key);
       mKeys.AppendElement(std::move(data));
       aResources.AddExternalImage(mId, key);
     }
 
     return key;
   }
 
 private:
@@ -318,22 +312,22 @@ SharedSurfacesChild::Share(SourceSurface
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aSurface);
   MOZ_ASSERT(aManager);
 
   // Each time the surface changes, the producers of SourceSurfaceSharedData
   // surfaces promise to increment the invalidation counter each time the
   // surface has changed. We can use this counter to determine whether or not
   // we should upate our paired ImageKey.
-  int32_t invalidations = aSurface->Invalidations();
+  Maybe<IntRect> dirtyRect = aSurface->TakeDirtyRect();
   SharedUserData* data = nullptr;
   nsresult rv = SharedSurfacesChild::ShareInternal(aSurface, &data);
   if (NS_SUCCEEDED(rv)) {
     MOZ_ASSERT(data);
-    aKey = data->UpdateKey(aManager, aResources, invalidations);
+    aKey = data->UpdateKey(aManager, aResources, dirtyRect);
   }
 
   return rv;
 }
 
 /* static */ nsresult
 SharedSurfacesChild::Share(ImageContainer* aContainer,
                            WebRenderLayerManager* aManager,
--- a/gfx/layers/ipc/WebRenderMessages.ipdlh
+++ b/gfx/layers/ipc/WebRenderMessages.ipdlh
@@ -127,16 +127,22 @@ struct OpUpdateImage {
 
 struct OpUpdateBlobImage {
   ImageDescriptor descriptor;
   OffsetRange bytes;
   ImageKey key;
   ImageIntRect dirtyRect;
 };
 
+struct OpUpdateExternalImage {
+  ExternalImageId externalImageId;
+  ImageKey key;
+  ImageIntRect dirtyRect;
+};
+
 struct OpDeleteImage {
   ImageKey key;
 };
 
 struct OpAddRawFont {
   OffsetRange bytes;
   uint32_t fontIndex;
   FontKey key;
@@ -173,12 +179,13 @@ union OpUpdateResource {
   OpDeleteImage;
   OpAddRawFont;
   OpAddFontDescriptor;
   OpDeleteFont;
   OpAddFontInstance;
   OpDeleteFontInstance;
   OpAddExternalImage;
   OpPushExternalImageForTexture;
+  OpUpdateExternalImage;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp
@@ -315,16 +315,24 @@ IpcResourceUpdateQueue::UpdateBlobImage(
   if (!bytes.length()) {
     return false;
   }
   mUpdates.AppendElement(layers::OpUpdateBlobImage(aDescriptor, bytes, aKey, aDirtyRect));
   return true;
 }
 
 void
+IpcResourceUpdateQueue::UpdateExternalImage(wr::ExternalImageId aExtId,
+                                            wr::ImageKey aKey,
+                                            ImageIntRect aDirtyRect)
+{
+  mUpdates.AppendElement(layers::OpUpdateExternalImage(aExtId, aKey, aDirtyRect));
+}
+
+void
 IpcResourceUpdateQueue::DeleteImage(ImageKey aKey)
 {
   mUpdates.AppendElement(layers::OpDeleteImage(aKey));
 }
 
 bool
 IpcResourceUpdateQueue::AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex)
 {
--- a/gfx/layers/wr/IpcResourceUpdateQueue.h
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.h
@@ -94,21 +94,19 @@ public:
                          const ImageDescriptor& aDescriptor,
                          Range<uint8_t> aBytes);
 
   bool UpdateBlobImage(wr::ImageKey aKey,
                        const ImageDescriptor& aDescriptor,
                        Range<uint8_t> aBytes,
                        ImageIntRect aDirtyRect);
 
-  void UpdateExternalImage(ImageKey aKey,
-                           const ImageDescriptor& aDescriptor,
-                           ExternalImageId aExtID,
-                           wr::WrExternalImageBufferType aBufferType,
-                           uint8_t aChannelIndex = 0);
+  void UpdateExternalImage(ExternalImageId aExtID,
+                           ImageKey aKey,
+                           ImageIntRect aDirtyRect);
 
   void DeleteImage(wr::ImageKey aKey);
 
   bool AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
 
   bool AddFontDescriptor(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
 
   void DeleteFont(wr::FontKey aKey);
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -348,16 +348,23 @@ WebRenderBridgeParent::UpdateResources(c
         const auto& op = cmd.get_OpPushExternalImageForTexture();
         CompositableTextureHostRef texture;
         texture = TextureHost::AsTextureHost(op.textureParent());
         if (!PushExternalImageForTexture(op.externalImageId(), op.key(), texture, op.isUpdate(), aUpdates)) {
           return false;
         }
         break;
       }
+      case OpUpdateResource::TOpUpdateExternalImage: {
+        const auto& op = cmd.get_OpUpdateExternalImage();
+        if (!UpdateExternalImage(op.externalImageId(), op.key(), op.dirtyRect(), aUpdates)) {
+          return false;
+        }
+        break;
+      }
       case OpUpdateResource::TOpAddRawFont: {
         const auto& op = cmd.get_OpAddRawFont();
         wr::Vec<uint8_t> bytes;
         if (!reader.Read(op.bytes(), bytes)) {
           return false;
         }
         aUpdates.AddRawFont(op.key(), bytes, op.fontIndex());
         break;
@@ -513,16 +520,64 @@ WebRenderBridgeParent::PushExternalImage
     aResources.AddImage(keys[0], descriptor, data);
   }
 
   dSurf->Unmap();
 
   return true;
 }
 
+bool
+WebRenderBridgeParent::UpdateExternalImage(wr::ExternalImageId aExtId,
+                                           wr::ImageKey aKey,
+                                           const ImageIntRect& aDirtyRect,
+                                           wr::TransactionBuilder& aResources)
+{
+  Range<wr::ImageKey> keys(&aKey, 1);
+  // Check if key is obsoleted.
+  if (keys[0].mNamespace != mIdNamespace) {
+    return true;
+  }
+
+  uint64_t imageId = wr::AsUint64(aExtId);
+  if (mSharedSurfaceIds.find(imageId) == mSharedSurfaceIds.end()) {
+    gfxCriticalNote << "Updating unknown shared surface: " << wr::AsUint64(aExtId);
+    return false;
+  }
+
+  RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Get(aExtId);
+  if (!dSurf) {
+    gfxCriticalNote << "Shared surface does not exist for extId:" << wr::AsUint64(aExtId);
+    return false;
+  }
+
+  if (!gfxEnv::EnableWebRenderRecording()) {
+    wr::ImageDescriptor descriptor(dSurf->GetSize(), dSurf->Stride(),
+                                   dSurf->GetFormat());
+    aResources.UpdateExternalImageWithDirtyRect(aKey, descriptor, aExtId,
+                                                wr::WrExternalImageBufferType::ExternalBuffer,
+                                                wr::ToDeviceUintRect(aDirtyRect),
+                                                0);
+    return true;
+  }
+
+  DataSourceSurface::ScopedMap map(dSurf, DataSourceSurface::READ);
+  if (!map.IsMapped()) {
+    gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:" << wr::AsUint64(aExtId);
+    return false;
+  }
+
+  IntSize size = dSurf->GetSize();
+  wr::ImageDescriptor descriptor(size, map.GetStride(), dSurf->GetFormat());
+  wr::Vec<uint8_t> data;
+  data.PushBytes(Range<uint8_t>(map.GetData(), size.height * map.GetStride()));
+  aResources.UpdateImageBuffer(keys[0], descriptor, data);
+  return true;
+}
+
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourceUpdates,
                                            nsTArray<RefCountedShmem>&& aSmallShmems,
                                            nsTArray<ipc::Shmem>&& aLargeShmems)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -204,16 +204,19 @@ private:
                               uint32_t aPaintSequenceNumber);
 
   bool UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
                        const nsTArray<RefCountedShmem>& aSmallShmems,
                        const nsTArray<ipc::Shmem>& aLargeShmems,
                        wr::TransactionBuilder& aUpdates);
   bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
                         wr::TransactionBuilder& aResources);
+  bool UpdateExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
+                           const ImageIntRect& aDirtyRect,
+                           wr::TransactionBuilder& aResources);
 
   bool PushExternalImageForTexture(wr::ExternalImageId aExtId,
                                    wr::ImageKey aKey,
                                    TextureHost* aTexture,
                                    bool aIsUpdate,
                                    wr::TransactionBuilder& aResources);
 
   void AddPipelineIdForCompositable(const wr::PipelineId& aPipelineIds,
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -7,17 +7,16 @@
 #ifndef MOZILLA_LAYERS_RENDERTHREAD_H
 #define MOZILLA_LAYERS_RENDERTHREAD_H
 
 #include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
 #include "base/platform_thread.h"       // for PlatformThreadId
 #include "base/thread.h"                // for Thread
 #include "base/message_loop.h"
 #include "nsISupportsImpl.h"
-#include "nsRefPtrHashtable.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/layers/SynchronousTask.h"
 
 #include <list>
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -634,16 +634,33 @@ TransactionBuilder::UpdateExternalImage(
                                             aKey,
                                             &aDescriptor,
                                             aExtID,
                                             aBufferType,
                                             aChannelIndex);
 }
 
 void
+TransactionBuilder::UpdateExternalImageWithDirtyRect(ImageKey aKey,
+                                                     const ImageDescriptor& aDescriptor,
+                                                     ExternalImageId aExtID,
+                                                     wr::WrExternalImageBufferType aBufferType,
+                                                     const wr::DeviceUintRect& aDirtyRect,
+                                                     uint8_t aChannelIndex)
+{
+  wr_resource_updates_update_external_image_with_dirty_rect(mTxn,
+                                                            aKey,
+                                                            &aDescriptor,
+                                                            aExtID,
+                                                            aBufferType,
+                                                            aChannelIndex,
+                                                            aDirtyRect);
+}
+
+void
 TransactionBuilder::DeleteImage(ImageKey aKey)
 {
   wr_resource_updates_delete_image(mTxn, aKey);
 }
 
 void
 TransactionBuilder::AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex)
 {
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -115,16 +115,23 @@ public:
                        const wr::DeviceUintRect& aDirtyRect);
 
   void UpdateExternalImage(ImageKey aKey,
                            const ImageDescriptor& aDescriptor,
                            ExternalImageId aExtID,
                            wr::WrExternalImageBufferType aBufferType,
                            uint8_t aChannelIndex = 0);
 
+  void UpdateExternalImageWithDirtyRect(ImageKey aKey,
+                                        const ImageDescriptor& aDescriptor,
+                                        ExternalImageId aExtID,
+                                        wr::WrExternalImageBufferType aBufferType,
+                                        const wr::DeviceUintRect& aDirtyRect,
+                                        uint8_t aChannelIndex = 0);
+
   void DeleteImage(wr::ImageKey aKey);
 
   void AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex);
 
   void AddFontDescriptor(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex);
 
   void DeleteFont(wr::FontKey aKey);
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1299,16 +1299,40 @@ pub extern "C" fn wr_resource_updates_up
                 image_type: image_type.to_wr(),
             }
         ),
         None
     );
 }
 
 #[no_mangle]
+pub extern "C" fn wr_resource_updates_update_external_image_with_dirty_rect(
+    txn: &mut Transaction,
+    key: WrImageKey,
+    descriptor: &WrImageDescriptor,
+    external_image_id: WrExternalImageId,
+    image_type: WrExternalImageBufferType,
+    channel_index: u8,
+    dirty_rect: DeviceUintRect,
+) {
+    txn.update_image(
+        key,
+        descriptor.into(),
+        ImageData::External(
+            ExternalImageData {
+                id: external_image_id.into(),
+                channel_index,
+                image_type: image_type.to_wr(),
+            }
+        ),
+        Some(dirty_rect)
+    );
+}
+
+#[no_mangle]
 pub extern "C" fn wr_resource_updates_update_blob_image(
     txn: &mut Transaction,
     image_key: WrImageKey,
     descriptor: &WrImageDescriptor,
     bytes: &mut WrVecU8,
     dirty_rect: DeviceUintRect,
 ) {
     txn.update_image(
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -1579,16 +1579,26 @@ void wr_resource_updates_update_external
                                                WrImageKey aKey,
                                                const WrImageDescriptor *aDescriptor,
                                                WrExternalImageId aExternalImageId,
                                                WrExternalImageBufferType aImageType,
                                                uint8_t aChannelIndex)
 WR_FUNC;
 
 WR_INLINE
+void wr_resource_updates_update_external_image_with_dirty_rect(Transaction *aTxn,
+                                                               WrImageKey aKey,
+                                                               const WrImageDescriptor *aDescriptor,
+                                                               WrExternalImageId aExternalImageId,
+                                                               WrExternalImageBufferType aImageType,
+                                                               uint8_t aChannelIndex,
+                                                               DeviceUintRect aDirtyRect)
+WR_FUNC;
+
+WR_INLINE
 void wr_resource_updates_update_image(Transaction *aTxn,
                                       WrImageKey aKey,
                                       const WrImageDescriptor *aDescriptor,
                                       WrVecU8 *aBytes)
 WR_FUNC;
 
 WR_INLINE
 uintptr_t wr_root_scroll_node_id()
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -614,41 +614,69 @@ imgFrame::ImageUpdated(const nsIntRect& 
   return ImageUpdatedInternal(aUpdateRect);
 }
 
 nsresult
 imgFrame::ImageUpdatedInternal(const nsIntRect& aUpdateRect)
 {
   mMonitor.AssertCurrentThreadOwns();
 
-  mDecoded.UnionRect(mDecoded, aUpdateRect);
-
   // Clamp to the frame rect to ensure that decoder bugs don't result in a
   // decoded rect that extends outside the bounds of the frame rect.
-  mDecoded.IntersectRect(mDecoded, mFrameRect);
+  IntRect updateRect = mFrameRect.Intersect(aUpdateRect);
+  if (updateRect.IsEmpty()) {
+    return NS_OK;
+  }
+
+  mDecoded.UnionRect(mDecoded, updateRect);
+
+  // Paletted images cannot invalidate.
+  if (mPalettedImageData) {
+    return NS_OK;
+  }
 
   // Update our invalidation counters for any consumers watching for changes
   // in the surface.
   if (mRawSurface) {
-    mRawSurface->Invalidate();
+    mRawSurface->Invalidate(updateRect);
   }
   if (mLockedSurface && mRawSurface != mLockedSurface) {
-    mLockedSurface->Invalidate();
+    mLockedSurface->Invalidate(updateRect);
   }
   return NS_OK;
 }
 
 void
 imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
                  bool aFinalize /* = true */)
 {
   MonitorAutoLock lock(mMonitor);
   MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
 
-  ImageUpdatedInternal(GetRect());
+  if (mPalettedImageData) {
+    ImageUpdatedInternal(mFrameRect);
+  } else if (!mDecoded.IsEqualEdges(mFrameRect)) {
+    // The decoder should have produced rows starting from either the bottom or
+    // the top of the image. We need to calculate the region for which we have
+    // not yet invalidated.
+    IntRect delta(0, 0, mFrameRect.width, 0);
+    if (mDecoded.y == 0) {
+      delta.y = mDecoded.height;
+      delta.height = mFrameRect.height - mDecoded.height;
+    } else if (mDecoded.y + mDecoded.height == mFrameRect.height) {
+      delta.height = mFrameRect.height - mDecoded.y;
+    } else {
+      MOZ_ASSERT_UNREACHABLE("Decoder only updated middle of image!");
+      delta = mFrameRect;
+    }
+
+    ImageUpdatedInternal(delta);
+  }
+
+  MOZ_ASSERT(mDecoded.IsEqualEdges(mFrameRect));
 
   if (aFinalize) {
     FinalizeSurfaceInternal();
   }
 
   mFinished = true;
 
   // The image is now complete, wake up anyone who's waiting.
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -555,17 +555,16 @@ struct RuntimeSizes
 {
 #define FOR_EACH_SIZE(macro) \
     macro(_, MallocHeap, object) \
     macro(_, MallocHeap, atomsTable) \
     macro(_, MallocHeap, atomsMarkBitmaps) \
     macro(_, MallocHeap, contexts) \
     macro(_, MallocHeap, temporary) \
     macro(_, MallocHeap, interpreterStack) \
-    macro(_, MallocHeap, mathCache) \
     macro(_, MallocHeap, sharedImmutableStringsCache) \
     macro(_, MallocHeap, sharedIntlData) \
     macro(_, MallocHeap, uncompressedSourceCache) \
     macro(_, MallocHeap, scriptData) \
     macro(_, MallocHeap, tracelogger) \
     macro(_, MallocHeap, wasmRuntime) \
     macro(_, MallocHeap, jitLazyLink)
 
--- a/js/src/ds/MemoryProtectionExceptionHandler.cpp
+++ b/js/src/ds/MemoryProtectionExceptionHandler.cpp
@@ -113,17 +113,17 @@ MemoryProtectionExceptionHandler::isDisa
 #if defined(XP_WIN) && defined(MOZ_ASAN)
     // Under Windows ASan, WasmFaultHandler registers itself at 'last' priority
     // in order to let ASan's ShadowExceptionHandler stay at 'first' priority.
     // Unfortunately that results in spurious wasm faults passing through the
     // MemoryProtectionExceptionHandler, which breaks its assumption that any
     // faults it sees are fatal. Just disable this handler in that case, as the
     // crash annotations provided here are not critical for ASan builds.
     return true;
-#elif defined(RELEASE_OR_BETA)
+#elif !defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
     // Disable the exception handler for Beta and Release builds.
     return true;
 #else
     return false;
 #endif
 }
 
 void
--- a/js/src/ds/Nestable.h
+++ b/js/src/ds/Nestable.h
@@ -2,16 +2,19 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ds_Nestable_h
 #define ds_Nestable_h
 
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+
 namespace js {
 
 // A base class for nestable structures.
 template <typename Concrete>
 class MOZ_STACK_CLASS Nestable
 {
     Concrete** stack_;
     Concrete*  enclosing_;
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BytecodeControlStructures.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "frontend/BytecodeControlStructures.h"
+
+#include "frontend/BytecodeEmitter.h"
+#include "frontend/EmitterScope.h"
+
+using namespace js;
+using namespace js::frontend;
+
+NestableControl::NestableControl(BytecodeEmitter* bce, StatementKind kind)
+  : Nestable<NestableControl>(&bce->innermostNestableControl),
+    kind_(kind),
+    emitterScope_(bce->innermostEmitterScopeNoCheck())
+{}
+
+BreakableControl::BreakableControl(BytecodeEmitter* bce, StatementKind kind)
+  : NestableControl(bce, kind)
+{
+    MOZ_ASSERT(is<BreakableControl>());
+}
+
+bool
+BreakableControl::patchBreaks(BytecodeEmitter* bce)
+{
+    return bce->emitJumpTargetAndPatch(breaks);
+}
+
+LabelControl::LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
+  : BreakableControl(bce, StatementKind::Label),
+    label_(bce->cx, label),
+    startOffset_(startOffset)
+{}
+
+LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
+  : BreakableControl(bce, loopKind),
+    tdzCache_(bce),
+    continueTarget({ -1 })
+{
+    MOZ_ASSERT(is<LoopControl>());
+
+    LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
+
+    stackDepth_ = bce->stackDepth;
+    loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
+
+    int loopSlots;
+    if (loopKind == StatementKind::Spread) {
+        // The iterator next method, the iterator, the result array, and
+        // the current array index are on the stack.
+        loopSlots = 4;
+    } else if (loopKind == StatementKind::ForOfLoop) {
+        // The iterator next method, the iterator, and the current value
+        // are on the stack.
+        loopSlots = 3;
+    } else if (loopKind == StatementKind::ForInLoop) {
+        // The iterator and the current value are on the stack.
+        loopSlots = 2;
+    } else {
+        // No additional loop values are on the stack.
+        loopSlots = 0;
+    }
+
+    MOZ_ASSERT(loopSlots <= stackDepth_);
+
+    if (enclosingLoop) {
+        canIonOsr_ = (enclosingLoop->canIonOsr_ &&
+                      stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
+    } else {
+        canIonOsr_ = stackDepth_ == loopSlots;
+    }
+}
+
+bool
+LoopControl::emitSpecialBreakForDone(BytecodeEmitter* bce)
+{
+    // This doesn't pop stack values, nor handle any other controls.
+    // Should be called on the toplevel of the loop.
+    MOZ_ASSERT(bce->stackDepth == stackDepth_);
+    MOZ_ASSERT(bce->innermostNestableControl == this);
+
+    if (!bce->newSrcNote(SRC_BREAK))
+        return false;
+    if (!bce->emitJump(JSOP_GOTO, &breaks))
+        return false;
+
+    return true;
+}
+
+bool
+LoopControl::patchBreaksAndContinues(BytecodeEmitter* bce)
+{
+    MOZ_ASSERT(continueTarget.offset != -1);
+    if (!patchBreaks(bce))
+        return false;
+    bce->patchJumpsToTarget(continues, continueTarget);
+    return true;
+}
+
+TryFinallyControl::TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
+  : NestableControl(bce, kind),
+    emittingSubroutine_(false)
+{
+    MOZ_ASSERT(is<TryFinallyControl>());
+}
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BytecodeControlStructures.h
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef frontend_BytecodeControlStructures_h
+#define frontend_BytecodeControlStructures_h
+
+#include "mozilla/Attributes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "ds/Nestable.h"
+#include "frontend/JumpList.h"
+#include "frontend/SharedContext.h"
+#include "frontend/TDZCheckCache.h"
+#include "gc/Rooting.h"
+#include "vm/StringType.h"
+
+namespace js {
+namespace frontend {
+
+struct BytecodeEmitter;
+class EmitterScope;
+
+class NestableControl : public Nestable<NestableControl>
+{
+    StatementKind kind_;
+
+    // The innermost scope when this was pushed.
+    EmitterScope* emitterScope_;
+
+  protected:
+    NestableControl(BytecodeEmitter* bce, StatementKind kind);
+
+  public:
+    using Nestable<NestableControl>::enclosing;
+    using Nestable<NestableControl>::findNearest;
+
+    StatementKind kind() const {
+        return kind_;
+    }
+
+    EmitterScope* emitterScope() const {
+        return emitterScope_;
+    }
+
+    template <typename T> bool is() const;
+
+    template <typename T> T& as() {
+        MOZ_ASSERT(this->is<T>());
+        return static_cast<T&>(*this);
+    }
+};
+
+class BreakableControl : public NestableControl
+{
+  public:
+    // Offset of the last break.
+    JumpList breaks;
+
+    BreakableControl(BytecodeEmitter* bce, StatementKind kind);
+
+    MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce);
+};
+template <>
+inline bool
+NestableControl::is<BreakableControl>() const
+{
+    return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
+}
+
+class LabelControl : public BreakableControl
+{
+    RootedAtom label_;
+
+    // The code offset when this was pushed. Used for effectfulness checking.
+    ptrdiff_t startOffset_;
+
+  public:
+    LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset);
+
+    HandleAtom label() const {
+        return label_;
+    }
+
+    ptrdiff_t startOffset() const {
+        return startOffset_;
+    }
+};
+template <>
+inline bool
+NestableControl::is<LabelControl>() const
+{
+    return kind_ == StatementKind::Label;
+}
+
+class LoopControl : public BreakableControl
+{
+    // Loops' children are emitted in dominance order, so they can always
+    // have a TDZCheckCache.
+    TDZCheckCache tdzCache_;
+
+    // Stack depth when this loop was pushed on the control stack.
+    int32_t stackDepth_;
+
+    // The loop nesting depth. Used as a hint to Ion.
+    uint32_t loopDepth_;
+
+    // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
+    bool canIonOsr_;
+
+  public:
+    // The target of continue statement jumps, e.g., the update portion of a
+    // for(;;) loop.
+    JumpTarget continueTarget;
+
+    // Offset of the last continue in the loop.
+    JumpList continues;
+
+    LoopControl(BytecodeEmitter* bce, StatementKind loopKind);
+
+    uint32_t loopDepth() const {
+        return loopDepth_;
+    }
+
+    bool canIonOsr() const {
+        return canIonOsr_;
+    }
+
+    MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce);
+    MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce);
+};
+template <>
+inline bool
+NestableControl::is<LoopControl>() const
+{
+    return StatementKindIsLoop(kind_);
+}
+
+class TryFinallyControl : public NestableControl
+{
+    bool emittingSubroutine_;
+
+  public:
+    // The subroutine when emitting a finally block.
+    JumpList gosubs;
+
+    TryFinallyControl(BytecodeEmitter* bce, StatementKind kind);
+
+    void setEmittingSubroutine() {
+        emittingSubroutine_ = true;
+    }
+
+    bool emittingSubroutine() const {
+        return emittingSubroutine_;
+    }
+};
+template <>
+inline bool
+NestableControl::is<TryFinallyControl>() const
+{
+    return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
+}
+
+} /* namespace frontend */
+} /* namespace js */
+
+#endif /* frontend_BytecodeControlStructures_h */
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -19,17 +19,23 @@
 #include <string.h>
 
 #include "jsapi.h"
 #include "jsnum.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "ds/Nestable.h"
+#include "frontend/BytecodeControlStructures.h"
+#include "frontend/EmitterScope.h"
+#include "frontend/ForOfLoopControl.h"
+#include "frontend/IfEmitter.h"
 #include "frontend/Parser.h"
+#include "frontend/TDZCheckCache.h"
+#include "frontend/TryEmitter.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/Debugger.h"
 #include "vm/GeneratorObject.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/JSScript.h"
 #include "vm/Stack.h"
@@ -50,2461 +56,31 @@ using mozilla::DebugOnly;
 using mozilla::Maybe;
 using mozilla::Nothing;
 using mozilla::NumberEqualsInt32;
 using mozilla::NumberIsInt32;
 using mozilla::PodCopy;
 using mozilla::Some;
 using mozilla::Unused;
 
-class BreakableControl;
-class LabelControl;
-class LoopControl;
-class ForOfLoopControl;
-class TryFinallyControl;
-
 static bool
 ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn)
 {
     // The few node types listed below are exceptions to the usual
     // location-source-note-emitting code in BytecodeEmitter::emitTree().
     // Single-line `while` loops and C-style `for` loops require careful
     // handling to avoid strange stepping behavior.
     // Functions usually shouldn't have location information (bug 1431202).
 
     ParseNodeKind kind = pn->getKind();
     return kind == ParseNodeKind::While ||
            kind == ParseNodeKind::For ||
            kind == ParseNodeKind::Function;
 }
 
-// A cache that tracks Temporal Dead Zone (TDZ) checks, so that any use of a
-// lexical variable that's dominated by an earlier use, or by evaluation of its
-// declaration (which will initialize it, perhaps to |undefined|), doesn't have
-// to redundantly check that the lexical variable has been initialized
-//
-// Each basic block should have a TDZCheckCache in scope. Some NestableControl
-// subclasses contain a TDZCheckCache.
-//
-// When a scope containing lexical variables is entered, all such variables are
-// marked as CheckTDZ.  When a lexical variable is accessed, its entry is
-// checked.  If it's CheckTDZ, a JSOP_CHECKLEXICAL is emitted and then the
-// entry is marked DontCheckTDZ.  If it's DontCheckTDZ, no check is emitted
-// because a prior check would have already failed.  Finally, because
-// evaluating a lexical variable declaration initializes it (after any
-// initializer is evaluated), evaluating a lexical declaration marks its entry
-// as DontCheckTDZ.
-class BytecodeEmitter::TDZCheckCache : public Nestable<BytecodeEmitter::TDZCheckCache>
-{
-    PooledMapPtr<CheckTDZMap> cache_;
-
-    MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
-        return cache_ || cache_.acquire(bce->cx);
-    }
-
-  public:
-    explicit TDZCheckCache(BytecodeEmitter* bce)
-      : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache),
-        cache_(bce->cx->frontendCollectionPool())
-    { }
-
-    Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name);
-    MOZ_MUST_USE bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, MaybeCheckTDZ check);
-};
-
-class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl>
-{
-    StatementKind kind_;
-
-    // The innermost scope when this was pushed.
-    EmitterScope* emitterScope_;
-
-  protected:
-    NestableControl(BytecodeEmitter* bce, StatementKind kind)
-      : Nestable<NestableControl>(&bce->innermostNestableControl),
-        kind_(kind),
-        emitterScope_(bce->innermostEmitterScopeNoCheck())
-    { }
-
-  public:
-    using Nestable<NestableControl>::enclosing;
-    using Nestable<NestableControl>::findNearest;
-
-    StatementKind kind() const {
-        return kind_;
-    }
-
-    EmitterScope* emitterScope() const {
-        return emitterScope_;
-    }
-
-    template <typename T>
-    bool is() const;
-
-    template <typename T>
-    T& as() {
-        MOZ_ASSERT(this->is<T>());
-        return static_cast<T&>(*this);
-    }
-};
-
-// Template specializations are disallowed in different namespaces; specialize
-// all the NestableControl subtypes up front.
-namespace js {
-namespace frontend {
-
-template <>
-bool
-BytecodeEmitter::NestableControl::is<BreakableControl>() const
-{
-    return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
-}
-
-template <>
-bool
-BytecodeEmitter::NestableControl::is<LabelControl>() const
-{
-    return kind_ == StatementKind::Label;
-}
-
-template <>
-bool
-BytecodeEmitter::NestableControl::is<LoopControl>() const
-{
-    return StatementKindIsLoop(kind_);
-}
-
-template <>
-bool
-BytecodeEmitter::NestableControl::is<ForOfLoopControl>() const
-{
-    return kind_ == StatementKind::ForOfLoop;
-}
-
-template <>
-bool
-BytecodeEmitter::NestableControl::is<TryFinallyControl>() const
-{
-    return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
-}
-
-} // namespace frontend
-} // namespace js
-
-class BreakableControl : public BytecodeEmitter::NestableControl
-{
-  public:
-    // Offset of the last break.
-    JumpList breaks;
-
-    BreakableControl(BytecodeEmitter* bce, StatementKind kind)
-      : NestableControl(bce, kind)
-    {
-        MOZ_ASSERT(is<BreakableControl>());
-    }
-
-    MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce) {
-        return bce->emitJumpTargetAndPatch(breaks);
-    }
-};
-
-class LabelControl : public BreakableControl
-{
-    RootedAtom label_;
-
-    // The code offset when this was pushed. Used for effectfulness checking.
-    ptrdiff_t startOffset_;
-
-  public:
-    LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
-      : BreakableControl(bce, StatementKind::Label),
-        label_(bce->cx, label),
-        startOffset_(startOffset)
-    { }
-
-    HandleAtom label() const {
-        return label_;
-    }
-
-    ptrdiff_t startOffset() const {
-        return startOffset_;
-    }
-};
-
-class LoopControl : public BreakableControl
-{
-    // Loops' children are emitted in dominance order, so they can always
-    // have a TDZCheckCache.
-    BytecodeEmitter::TDZCheckCache tdzCache_;
-
-    // Stack depth when this loop was pushed on the control stack.
-    int32_t stackDepth_;
-
-    // The loop nesting depth. Used as a hint to Ion.
-    uint32_t loopDepth_;
-
-    // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
-    bool canIonOsr_;
-
-  public:
-    // The target of continue statement jumps, e.g., the update portion of a
-    // for(;;) loop.
-    JumpTarget continueTarget;
-
-    // Offset of the last continue in the loop.
-    JumpList continues;
-
-    LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
-      : BreakableControl(bce, loopKind),
-        tdzCache_(bce),
-        continueTarget({ -1 })
-    {
-        MOZ_ASSERT(is<LoopControl>());
-
-        LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
-
-        stackDepth_ = bce->stackDepth;
-        loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
-
-        int loopSlots;
-        if (loopKind == StatementKind::Spread) {
-            // The iterator next method, the iterator, the result array, and
-            // the current array index are on the stack.
-            loopSlots = 4;
-        } else if (loopKind == StatementKind::ForOfLoop) {
-            // The iterator next method, the iterator, and the current value
-            // are on the stack.
-            loopSlots = 3;
-        } else if (loopKind == StatementKind::ForInLoop) {
-            // The iterator and the current value are on the stack.
-            loopSlots = 2;
-        } else {
-            // No additional loop values are on the stack.
-            loopSlots = 0;
-        }
-
-        MOZ_ASSERT(loopSlots <= stackDepth_);
-
-        if (enclosingLoop) {
-            canIonOsr_ = (enclosingLoop->canIonOsr_ &&
-                          stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
-        } else {
-            canIonOsr_ = stackDepth_ == loopSlots;
-        }
-    }
-
-    uint32_t loopDepth() const {
-        return loopDepth_;
-    }
-
-    bool canIonOsr() const {
-        return canIonOsr_;
-    }
-
-    MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce) {
-        // This doesn't pop stack values, nor handle any other controls.
-        // Should be called on the toplevel of the loop.
-        MOZ_ASSERT(bce->stackDepth == stackDepth_);
-        MOZ_ASSERT(bce->innermostNestableControl == this);
-
-        if (!bce->newSrcNote(SRC_BREAK))
-            return false;
-        if (!bce->emitJump(JSOP_GOTO, &breaks))
-            return false;
-
-        return true;
-    }
-
-    MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce) {
-        MOZ_ASSERT(continueTarget.offset != -1);
-        if (!patchBreaks(bce))
-            return false;
-        bce->patchJumpsToTarget(continues, continueTarget);
-        return true;
-    }
-};
-
-class TryFinallyControl : public BytecodeEmitter::NestableControl
-{
-    bool emittingSubroutine_;
-
-  public:
-    // The subroutine when emitting a finally block.
-    JumpList gosubs;
-
-    TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
-      : NestableControl(bce, kind),
-        emittingSubroutine_(false)
-    {
-        MOZ_ASSERT(is<TryFinallyControl>());
-    }
-
-    void setEmittingSubroutine() {
-        emittingSubroutine_ = true;
-    }
-
-    bool emittingSubroutine() const {
-        return emittingSubroutine_;
-    }
-};
-
-static inline void
-MarkAllBindingsClosedOver(LexicalScope::Data& data)
-{
-    TrailingNamesArray& names = data.trailingNames;
-    for (uint32_t i = 0; i < data.length; i++)
-        names[i] = BindingName(names[i].name(), true);
-}
-
-// A scope that introduces bindings.
-class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterScope>
-{
-    // The cache of bound names that may be looked up in the
-    // scope. Initially populated as the set of names this scope binds. As
-    // names are looked up in enclosing scopes, they are cached on the
-    // current scope.
-    PooledMapPtr<NameLocationMap> nameCache_;
-
-    // If this scope's cache does not include free names, such as the
-    // global scope, the NameLocation to return.
-    Maybe<NameLocation> fallbackFreeNameLocation_;
-
-    // True if there is a corresponding EnvironmentObject on the environment
-    // chain, false if all bindings are stored in frame slots on the stack.
-    bool hasEnvironment_;
-
-    // The number of enclosing environments. Used for error checking.
-    uint8_t environmentChainLength_;
-
-    // The next usable slot on the frame for not-closed over bindings.
-    //
-    // The initial frame slot when assigning slots to bindings is the
-    // enclosing scope's nextFrameSlot. For the first scope in a frame,
-    // the initial frame slot is 0.
-    uint32_t nextFrameSlot_;
-
-    // The index in the BytecodeEmitter's interned scope vector, otherwise
-    // ScopeNote::NoScopeIndex.
-    uint32_t scopeIndex_;
-
-    // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
-    // block scope note list. Otherwise ScopeNote::NoScopeNote.
-    uint32_t noteIndex_;
-
-    MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
-        return nameCache_.acquire(bce->cx);
-    }
-
-    template <typename BindingIter>
-    MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi) {
-        if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
-            bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
-        {
-            bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
-            return false;
-        }
-        return true;
-    }
-
-    MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce) {
-        uint32_t hops;
-        if (EmitterScope* emitterScope = enclosing(&bce))
-            hops = emitterScope->environmentChainLength_;
-        else
-            hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
-
-        if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
-            bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
-            return false;
-        }
-
-        environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
-        return true;
-    }
-
-    void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi) {
-        nextFrameSlot_ = bi.nextFrameSlot();
-        if (nextFrameSlot_ > bce->maxFixedSlots)
-            bce->maxFixedSlots = nextFrameSlot_;
-        MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&
-                      (bce->sc->asFunctionBox()->isGenerator() ||
-                       bce->sc->asFunctionBox()->isAsync()),
-                      bce->maxFixedSlots == 0);
-    }
-
-    MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation loc) {
-        NameLocationMap& cache = *nameCache_;
-        NameLocationMap::AddPtr p = cache.lookupForAdd(name);
-        MOZ_ASSERT(!p);
-        if (!cache.add(p, name, loc)) {
-            ReportOutOfMemory(bce->cx);
-            return false;
-        }
-        return true;
-    }
-
-    Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce, JSAtom* name) {
-        if (NameLocationMap::Ptr p = nameCache_->lookup(name))
-            return Some(p->value().wrapped);
-        if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name))
-            return fallbackFreeNameLocation_;
-        return Nothing();
-    }
-
-    friend bool BytecodeEmitter::needsImplicitThis();
-
-    EmitterScope* enclosing(BytecodeEmitter** bce) const {
-        // There is an enclosing scope with access to the same frame.
-        if (EmitterScope* inFrame = enclosingInFrame())
-            return inFrame;
-
-        // We are currently compiling the enclosing script, look in the
-        // enclosing BCE.
-        if ((*bce)->parent) {
-            *bce = (*bce)->parent;
-            return (*bce)->innermostEmitterScopeNoCheck();
-        }
-
-        return nullptr;
-    }
-
-    Scope* enclosingScope(BytecodeEmitter* bce) const {
-        if (EmitterScope* es = enclosing(&bce))
-            return es->scope(bce);
-
-        // The enclosing script is already compiled or the current script is the
-        // global script.
-        return bce->sc->compilationEnclosingScope();
-    }
-
-    static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name) {
-        // '.generator' cannot be accessed by name.
-        return name != bce->cx->names().dotGenerator;
-    }
-
-    static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops);
-    NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);
-
-    template <typename ScopeCreator>
-    MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
-    template <typename ScopeCreator>
-    MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
-    MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
-
-    MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
-                                             uint32_t slotEnd);
-
-  public:
-    explicit EmitterScope(BytecodeEmitter* bce)
-      : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
-        nameCache_(bce->cx->frontendCollectionPool()),
-        hasEnvironment_(false),
-        environmentChainLength_(0),
-        nextFrameSlot_(0),
-        scopeIndex_(ScopeNote::NoScopeIndex),
-        noteIndex_(ScopeNote::NoScopeNoteIndex)
-    { }
-
-    void dump(BytecodeEmitter* bce);
-
-    MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
-                                   Handle<LexicalScope::Data*> bindings);
-    MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
-    MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
-    MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
-    MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
-    MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc);
-    MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
-    MOZ_MUST_USE bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc);
-    MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
-    MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce);
-
-    MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);
-
-    uint32_t index() const {
-        MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?");
-        return scopeIndex_;
-    }
-
-    uint32_t noteIndex() const {
-        return noteIndex_;
-    }
-
-    Scope* scope(const BytecodeEmitter* bce) const {
-        return bce->scopeList.vector[index()];
-    }
-
-    bool hasEnvironment() const {
-        return hasEnvironment_;
-    }
-
-    // The first frame slot used.
-    uint32_t frameSlotStart() const {
-        if (EmitterScope* inFrame = enclosingInFrame())
-            return inFrame->nextFrameSlot_;
-        return 0;
-    }
-
-    // The last frame slot used + 1.
-    uint32_t frameSlotEnd() const {
-        return nextFrameSlot_;
-    }
-
-    EmitterScope* enclosingInFrame() const {
-        return Nestable<EmitterScope>::enclosing();
-    }
-
-    NameLocation lookup(BytecodeEmitter* bce, JSAtom* name) {
-        if (Maybe<NameLocation> loc = lookupInCache(bce, name))
-            return *loc;
-        return searchAndCache(bce, name);
-    }
-
-    Maybe<NameLocation> locationBoundInScope(JSAtom* name, EmitterScope* target);
-};
-
-void
-BytecodeEmitter::EmitterScope::dump(BytecodeEmitter* bce)
-{
-    fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()), this);
-
-    for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
-        const NameLocation& l = r.front().value();
-
-        JSAutoByteString bytes;
-        if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes))
-            return;
-        if (l.kind() != NameLocation::Kind::Dynamic)
-            fprintf(stdout, "  %s %s ", BindingKindString(l.bindingKind()), bytes.ptr());
-        else
-            fprintf(stdout, "  %s ", bytes.ptr());
-
-        switch (l.kind()) {
-          case NameLocation::Kind::Dynamic:
-            fprintf(stdout, "dynamic\n");
-            break;
-          case NameLocation::Kind::Global:
-            fprintf(stdout, "global\n");
-            break;
-          case NameLocation::Kind::Intrinsic:
-            fprintf(stdout, "intrinsic\n");
-            break;
-          case NameLocation::Kind::NamedLambdaCallee:
-            fprintf(stdout, "named lambda callee\n");
-            break;
-          case NameLocation::Kind::Import:
-            fprintf(stdout, "import\n");
-            break;
-          case NameLocation::Kind::ArgumentSlot:
-            fprintf(stdout, "arg slot=%u\n", l.argumentSlot());
-            break;
-          case NameLocation::Kind::FrameSlot:
-            fprintf(stdout, "frame slot=%u\n", l.frameSlot());
-            break;
-          case NameLocation::Kind::EnvironmentCoordinate:
-            fprintf(stdout, "environment hops=%u slot=%u\n",
-                    l.environmentCoordinate().hops(), l.environmentCoordinate().slot());
-            break;
-          case NameLocation::Kind::DynamicAnnexBVar:
-            fprintf(stdout, "dynamic annex b var\n");
-            break;
-        }
-    }
-
-    fprintf(stdout, "\n");
-}
-
-template <typename ScopeCreator>
-bool
-BytecodeEmitter::EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope)
-{
-    RootedScope enclosing(bce->cx, enclosingScope(bce));
-    Scope* scope = createScope(bce->cx, enclosing);
-    if (!scope)
-        return false;
-    hasEnvironment_ = scope->hasEnvironment();
-    scopeIndex_ = bce->scopeList.length();
-    return bce->scopeList.append(scope);
-}
-
-template <typename ScopeCreator>
-bool
-BytecodeEmitter::EmitterScope::internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope)
-{
-    MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX, "There can be only one body scope");
-    bce->bodyScopeIndex = bce->scopeList.length();
-    return internScope(bce, createScope);
-}
-
-bool
-BytecodeEmitter::EmitterScope::appendScopeNote(BytecodeEmitter* bce)
-{
-    MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
-               "Scope notes are not needed for body-level scopes.");
-    noteIndex_ = bce->scopeNoteList.length();
-    return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
-                                     enclosingInFrame() ? enclosingInFrame()->noteIndex()
-                                                        : ScopeNote::NoScopeNoteIndex);
-}
-
-#ifdef DEBUG
-static bool
-NameIsOnEnvironment(Scope* scope, JSAtom* name)
-{
-    for (BindingIter bi(scope); bi; bi++) {
-        // If found, the name must already be on the environment or an import,
-        // or else there is a bug in the closed-over name analysis in the
-        // Parser.
-        if (bi.name() == name) {
-            BindingLocation::Kind kind = bi.location().kind();
-
-            if (bi.hasArgumentSlot()) {
-                JSScript* script = scope->as<FunctionScope>().script();
-                if (!script->strict() && !script->functionHasParameterExprs()) {
-                    // Check for duplicate positional formal parameters.
-                    for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
-                        if (bi2.name() == name)
-                            kind = bi2.location().kind();
-                    }
-                }
-            }
-
-            return kind == BindingLocation::Kind::Global ||
-                   kind == BindingLocation::Kind::Environment ||
-                   kind == BindingLocation::Kind::Import;
-        }
-    }
-
-    // If not found, assume it's on the global or dynamically accessed.
-    return true;
-}
-#endif
-
-/* static */ NameLocation
-BytecodeEmitter::EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops)
-{
-    for (ScopeIter si(scope); si; si++) {
-        MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name));
-
-        bool hasEnv = si.hasSyntacticEnvironment();
-
-        switch (si.kind()) {
-          case ScopeKind::Function:
-            if (hasEnv) {
-                JSScript* script = si.scope()->as<FunctionScope>().script();
-                if (script->funHasExtensibleScope())
-                    return NameLocation::Dynamic();
-
-                for (BindingIter bi(si.scope()); bi; bi++) {
-                    if (bi.name() != name)
-                        continue;
-
-                    BindingLocation bindLoc = bi.location();
-                    if (bi.hasArgumentSlot() &&
-                        !script->strict() &&
-                        !script->functionHasParameterExprs())
-                    {
-                        // Check for duplicate positional formal parameters.
-                        for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
-                            if (bi2.name() == name)
-                                bindLoc = bi2.location();
-                        }
-                    }
-
-                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
-                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
-                }
-            }
-            break;
-
-          case ScopeKind::FunctionBodyVar:
-          case ScopeKind::ParameterExpressionVar:
-          case ScopeKind::Lexical:
-          case ScopeKind::NamedLambda:
-          case ScopeKind::StrictNamedLambda:
-          case ScopeKind::SimpleCatch:
-          case ScopeKind::Catch:
-            if (hasEnv) {
-                for (BindingIter bi(si.scope()); bi; bi++) {
-                    if (bi.name() != name)
-                        continue;
-
-                    // The name must already have been marked as closed
-                    // over. If this assertion is hit, there is a bug in the
-                    // name analysis.
-                    BindingLocation bindLoc = bi.location();
-                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
-                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
-                }
-            }
-            break;
-
-          case ScopeKind::Module:
-            if (hasEnv) {
-                for (BindingIter bi(si.scope()); bi; bi++) {
-                    if (bi.name() != name)
-                        continue;
-
-                    BindingLocation bindLoc = bi.location();
-
-                    // Imports are on the environment but are indirect
-                    // bindings and must be accessed dynamically instead of
-                    // using an EnvironmentCoordinate.
-                    if (bindLoc.kind() == BindingLocation::Kind::Import) {
-                        MOZ_ASSERT(si.kind() == ScopeKind::Module);
-                        return NameLocation::Import();
-                    }
-
-                    MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
-                    return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
-                }
-            }
-            break;
-
-          case ScopeKind::Eval:
-          case ScopeKind::StrictEval:
-            // As an optimization, if the eval doesn't have its own var
-            // environment and its immediate enclosing scope is a global
-            // scope, all accesses are global.
-            if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>())
-                return NameLocation::Global(BindingKind::Var);
-            return NameLocation::Dynamic();
-
-          case ScopeKind::Global:
-            return NameLocation::Global(BindingKind::Var);
-
-          case ScopeKind::With:
-          case ScopeKind::NonSyntactic:
-            return NameLocation::Dynamic();
-
-          case ScopeKind::WasmInstance:
-          case ScopeKind::WasmFunction:
-            MOZ_CRASH("No direct eval inside wasm functions");
-        }
-
-        if (hasEnv) {
-            MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
-            hops++;
-        }
-    }
-
-    MOZ_CRASH("Malformed scope chain");
-}
-
-NameLocation
-BytecodeEmitter::EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name)
-{
-    Maybe<NameLocation> loc;
-    uint8_t hops = hasEnvironment() ? 1 : 0;
-    DebugOnly<bool> inCurrentScript = enclosingInFrame();
-
-    // Start searching in the current compilation.
-    for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
-        loc = es->lookupInCache(bce, name);
-        if (loc) {
-            if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate)
-                *loc = loc->addHops(hops);
-            break;
-        }
-
-        if (es->hasEnvironment())
-            hops++;
-
-#ifdef DEBUG
-        if (!es->enclosingInFrame())
-            inCurrentScript = false;
-#endif
-    }
-
-    // If the name is not found in the current compilation, walk the Scope
-    // chain encompassing the compilation.
-    if (!loc) {
-        inCurrentScript = false;
-        loc = Some(searchInEnclosingScope(name, bce->sc->compilationEnclosingScope(), hops));
-    }
-
-    // Each script has its own frame. A free name that is accessed
-    // from an inner script must not be a frame slot access. If this
-    // assertion is hit, it is a bug in the free name analysis in the
-    // parser.
-    MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot);
-
-    // It is always correct to not cache the location. Ignore OOMs to make
-    // lookups infallible.
-    if (!putNameInCache(bce, name, *loc))
-        bce->cx->recoverFromOutOfMemory();
-
-    return *loc;
-}
-
-Maybe<NameLocation>
-BytecodeEmitter::EmitterScope::locationBoundInScope(JSAtom* name, EmitterScope* target)
-{
-    // The target scope must be an intra-frame enclosing scope of this
-    // one. Count the number of extra hops to reach it.
-    uint8_t extraHops = 0;
-    for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
-        if (es->hasEnvironment())
-            extraHops++;
-    }
-
-    // Caches are prepopulated with bound names. So if the name is bound in a
-    // particular scope, it must already be in the cache. Furthermore, don't
-    // consult the fallback location as we only care about binding names.
-    Maybe<NameLocation> loc;
-    if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
-        NameLocation l = p->value().wrapped;
-        if (l.kind() == NameLocation::Kind::EnvironmentCoordinate)
-            loc = Some(l.addHops(extraHops));
-        else
-            loc = Some(l);
-    }
-    return loc;
-}
-
-bool
-BytecodeEmitter::EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
-                                                      uint32_t slotEnd)
-{
-    // Lexical bindings throw ReferenceErrors if they are used before
-    // initialization. See ES6 8.1.1.1.6.
-    //
-    // For completeness, lexical bindings are initialized in ES6 by calling
-    // InitializeBinding, after which touching the binding will no longer
-    // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
-    // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
-    if (slotStart != slotEnd) {
-        if (!bce->emit1(JSOP_UNINITIALIZED))
-            return false;
-        for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
-            if (!bce->emitLocalOp(JSOP_INITLEXICAL, slot))
-                return false;
-        }
-        if (!bce->emit1(JSOP_POP))
-            return false;
-    }
-
-    return true;
-}
-
-bool
-BytecodeEmitter::EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce)
-{
-    return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
-                                            Handle<LexicalScope::Data*> bindings)
-{
-    MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    if (!ensureCache(bce))
-        return false;
-
-    // Marks all names as closed over if the context requires it. This
-    // cannot be done in the Parser as we may not know if the context requires
-    // all bindings to be closed over until after parsing is finished. For
-    // example, legacy generators require all bindings to be closed over but
-    // it is unknown if a function is a legacy generator until the first
-    // 'yield' expression is parsed.
-    //
-    // This is not a problem with other scopes, as all other scopes with
-    // bindings are body-level. At the time of their creation, whether or not
-    // the context requires all bindings to be closed over is already known.
-    if (bce->sc->allBindingsClosedOver())
-        MarkAllBindingsClosedOver(*bindings);
-
-    // Resolve bindings.
-    TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
-    uint32_t firstFrameSlot = frameSlotStart();
-    BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
-    for (; bi; bi++) {
-        if (!checkSlotLimits(bce, bi))
-            return false;
-
-        NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
-        if (!putNameInCache(bce, bi.name(), loc))
-            return false;
-
-        if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
-            return false;
-    }
-
-    updateFrameFixedSlots(bce, bi);
-
-    // Create and intern the VM scope.
-    auto createScope = [kind, bindings, firstFrameSlot](JSContext* cx,
-                                                        HandleScope enclosing)
-    {
-        return LexicalScope::create(cx, kind, bindings, firstFrameSlot, enclosing);
-    };
-    if (!internScope(bce, createScope))
-        return false;
-
-    if (ScopeKindIsInBody(kind) && hasEnvironment()) {
-        // After interning the VM scope we can get the scope index.
-        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHLEXICALENV))
-            return false;
-    }
-
-    // Lexical scopes need notes to be mapped from a pc.
-    if (!appendScopeNote(bce))
-        return false;
-
-    // Put frame slots in TDZ. Environment slots are poisoned during
-    // environment creation.
-    //
-    // This must be done after appendScopeNote to be considered in the extent
-    // of the scope.
-    if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd()))
-        return false;
-
-    return checkEnvironmentChainLength(bce);
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
-{
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-    MOZ_ASSERT(funbox->namedLambdaBindings());
-
-    if (!ensureCache(bce))
-        return false;
-
-    // See comment in enterLexical about allBindingsClosedOver.
-    if (funbox->allBindingsClosedOver())
-        MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
-
-    BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT, /* isNamedLambda = */ true);
-    MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee);
-
-    // The lambda name, if not closed over, is accessed via JSOP_CALLEE and
-    // not a frame slot. Do not update frame slot information.
-    NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
-    if (!putNameInCache(bce, bi.name(), loc))
-        return false;
-
-    bi++;
-    MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope");
-
-    auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
-        ScopeKind scopeKind =
-            funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda;
-        return LexicalScope::create(cx, scopeKind, funbox->namedLambdaBindings(),
-                                    LOCALNO_LIMIT, enclosing);
-    };
-    if (!internScope(bce, createScope))
-        return false;
-
-    return checkEnvironmentChainLength(bce);
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
-{
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    if (!ensureCache(bce))
-        return false;
-
-    // Parameter expressions var scopes have no pre-set bindings and are
-    // always extensible, as they are needed for eval.
-    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
-
-    // Create and intern the VM scope.
-    uint32_t firstFrameSlot = frameSlotStart();
-    auto createScope = [firstFrameSlot](JSContext* cx, HandleScope enclosing) {
-        return VarScope::create(cx, ScopeKind::ParameterExpressionVar,
-                                /* data = */ nullptr, firstFrameSlot,
-                                /* needsEnvironment = */ true, enclosing);
-    };
-    if (!internScope(bce, createScope))
-        return false;
-
-    MOZ_ASSERT(hasEnvironment());
-    if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
-        return false;
-
-    // The extra var scope needs a note to be mapped from a pc.
-    if (!appendScopeNote(bce))
-        return false;
-
-    return checkEnvironmentChainLength(bce);
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
-{
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    // If there are parameter expressions, there is an extra var scope.
-    if (!funbox->hasExtraBodyVarScope())
-        bce->setVarEmitterScope(this);
-
-    if (!ensureCache(bce))
-        return false;
-
-    // Resolve body-level bindings, if there are any.
-    auto bindings = funbox->functionScopeBindings();
-    Maybe<uint32_t> lastLexicalSlot;
-    if (bindings) {
-        NameLocationMap& cache = *nameCache_;
-
-        BindingIter bi(*bindings, funbox->hasParameterExprs);
-        for (; bi; bi++) {
-            if (!checkSlotLimits(bce, bi))
-                return false;
-
-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
-            NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
-
-            // The only duplicate bindings that occur are simple formal
-            // parameters, in which case the last position counts, so update the
-            // location.
-            if (p) {
-                MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
-                MOZ_ASSERT(!funbox->hasDestructuringArgs);
-                MOZ_ASSERT(!funbox->hasRest());
-                p->value() = loc;
-                continue;
-            }
-
-            if (!cache.add(p, bi.name(), loc)) {
-                ReportOutOfMemory(bce->cx);
-                return false;
-            }
-        }
-
-        updateFrameFixedSlots(bce, bi);
-    } else {
-        nextFrameSlot_ = 0;
-    }
-
-    // If the function's scope may be extended at runtime due to sloppy direct
-    // eval and there is no extra var scope, any names beyond the function
-    // scope must be accessed dynamically as we don't know if the name will
-    // become a 'var' binding due to direct eval.
-    if (!funbox->hasParameterExprs && funbox->hasExtensibleScope())
-        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
-
-    // In case of parameter expressions, the parameters are lexical
-    // bindings and have TDZ.
-    if (funbox->hasParameterExprs && nextFrameSlot_) {
-        uint32_t paramFrameSlotEnd = 0;
-        for (BindingIter bi(*bindings, true); bi; bi++) {
-            if (!BindingKindIsLexical(bi.kind()))
-                break;
-
-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
-            if (loc.kind() == NameLocation::Kind::FrameSlot) {
-                MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot());
-                paramFrameSlotEnd = loc.frameSlot() + 1;
-            }
-        }
-
-        if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd))
-            return false;
-    }
-
-    // Create and intern the VM scope.
-    auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
-        RootedFunction fun(cx, funbox->function());
-        return FunctionScope::create(cx, funbox->functionScopeBindings(),
-                                     funbox->hasParameterExprs,
-                                     funbox->needsCallObjectRegardlessOfBindings(),
-                                     fun, enclosing);
-    };
-    if (!internBodyScope(bce, createScope))
-        return false;
-
-    return checkEnvironmentChainLength(bce);
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
-{
-    MOZ_ASSERT(funbox->hasParameterExprs);
-    MOZ_ASSERT(funbox->extraVarScopeBindings() ||
-               funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    // The extra var scope is never popped once it's entered. It replaces the
-    // function scope as the var emitter scope.
-    bce->setVarEmitterScope(this);
-
-    if (!ensureCache(bce))
-        return false;
-
-    // Resolve body-level bindings, if there are any.
-    uint32_t firstFrameSlot = frameSlotStart();
-    if (auto bindings = funbox->extraVarScopeBindings()) {
-        BindingIter bi(*bindings, firstFrameSlot);
-        for (; bi; bi++) {
-            if (!checkSlotLimits(bce, bi))
-                return false;
-
-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
-            if (!putNameInCache(bce, bi.name(), loc))
-                return false;
-        }
-
-        updateFrameFixedSlots(bce, bi);
-    } else {
-        nextFrameSlot_ = firstFrameSlot;
-    }
-
-    // If the extra var scope may be extended at runtime due to sloppy
-    // direct eval, any names beyond the var scope must be accessed
-    // dynamically as we don't know if the name will become a 'var' binding
-    // due to direct eval.
-    if (funbox->hasExtensibleScope())
-        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
-
-    // Create and intern the VM scope.
-    auto createScope = [funbox, firstFrameSlot](JSContext* cx, HandleScope enclosing) {
-        return VarScope::create(cx, ScopeKind::FunctionBodyVar,
-                                funbox->extraVarScopeBindings(), firstFrameSlot,
-                                funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(),
-                                enclosing);
-    };
-    if (!internScope(bce, createScope))
-        return false;
-
-    if (hasEnvironment()) {
-        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
-            return false;
-    }
-
-    // The extra var scope needs a note to be mapped from a pc.
-    if (!appendScopeNote(bce))
-        return false;
-
-    return checkEnvironmentChainLength(bce);
-}
-
-class DynamicBindingIter : public BindingIter
-{
-  public:
-    explicit DynamicBindingIter(GlobalSharedContext* sc)
-      : BindingIter(*sc->bindings)
-    { }
-
-    explicit DynamicBindingIter(EvalSharedContext* sc)
-      : BindingIter(*sc->bindings, /* strict = */ false)
-    {
-        MOZ_ASSERT(!sc->strict());
-    }
-
-    JSOp bindingOp() const {
-        switch (kind()) {
-          case BindingKind::Var:
-            return JSOP_DEFVAR;
-          case BindingKind::Let:
-            return JSOP_DEFLET;
-          case BindingKind::Const:
-            return JSOP_DEFCONST;
-          default:
-            MOZ_CRASH("Bad BindingKind");
-        }
-    }
-};
-
-bool
-BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
-{
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    bce->setVarEmitterScope(this);
-
-    if (!ensureCache(bce))
-        return false;
-
-    if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
-        // In self-hosting, it is incorrect to consult the global scope because
-        // self-hosted scripts are cloned into their target compartments before
-        // they are run. Instead of Global, Intrinsic is used for all names.
-        //
-        // Intrinsic lookups are redirected to the special intrinsics holder
-        // in the global object, into which any missing values are cloned
-        // lazily upon first access.
-        fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
-
-        auto createScope = [](JSContext* cx, HandleScope enclosing) {
-            MOZ_ASSERT(!enclosing);
-            return &cx->global()->emptyGlobalScope();
-        };
-        return internBodyScope(bce, createScope);
-    }
-
-    // Resolve binding names and emit DEF{VAR,LET,CONST} prologue ops.
-    if (globalsc->bindings) {
-        for (DynamicBindingIter bi(globalsc); bi; bi++) {
-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
-            JSAtom* name = bi.name();
-            if (!putNameInCache(bce, name, loc))
-                return false;
-
-            // Define the name in the prologue. Do not emit DEFVAR for
-            // functions that we'll emit DEFFUN for.
-            if (bi.isTopLevelFunction())
-                continue;
-
-            if (!bce->emitAtomOp(name, bi.bindingOp()))
-                return false;
-        }
-    }
-
-    // Note that to save space, we don't add free names to the cache for
-    // global scopes. They are assumed to be global vars in the syntactic
-    // global scope, dynamic accesses under non-syntactic global scope.
-    if (globalsc->scopeKind() == ScopeKind::Global)
-        fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
-    else
-        fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
-
-    auto createScope = [globalsc](JSContext* cx, HandleScope enclosing) {
-        MOZ_ASSERT(!enclosing);
-        return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
-    };
-    return internBodyScope(bce, createScope);
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
-{
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    bce->setVarEmitterScope(this);
-
-    if (!ensureCache(bce))
-        return false;
-
-    // For simplicity, treat all free name lookups in eval scripts as dynamic.
-    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
-
-    // Create the `var` scope. Note that there is also a lexical scope, created
-    // separately in emitScript().
-    auto createScope = [evalsc](JSContext* cx, HandleScope enclosing) {
-        ScopeKind scopeKind = evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
-        return EvalScope::create(cx, scopeKind, evalsc->bindings, enclosing);
-    };
-    if (!internBodyScope(bce, createScope))
-        return false;
-
-    if (hasEnvironment()) {
-        if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
-            return false;
-    } else {
-        // Resolve binding names and emit DEFVAR prologue ops if we don't have
-        // an environment (i.e., a sloppy eval not in a parameter expression).
-        // Eval scripts always have their own lexical scope, but non-strict
-        // scopes may introduce 'var' bindings to the nearest var scope.
-        //
-        // TODO: We may optimize strict eval bindings in the future to be on
-        // the frame. For now, handle everything dynamically.
-        if (!hasEnvironment() && evalsc->bindings) {
-            for (DynamicBindingIter bi(evalsc); bi; bi++) {
-                MOZ_ASSERT(bi.bindingOp() == JSOP_DEFVAR);
-
-                if (bi.isTopLevelFunction())
-                    continue;
-
-                if (!bce->emitAtomOp(bi.name(), JSOP_DEFVAR))
-                    return false;
-            }
-        }
-
-        // As an optimization, if the eval does not have its own var
-        // environment and is directly enclosed in a global scope, then all
-        // free name lookups are global.
-        if (scope(bce)->enclosing()->is<GlobalScope>())
-            fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
-    }
-
-    return true;
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
-{
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    bce->setVarEmitterScope(this);
-
-    if (!ensureCache(bce))
-        return false;
-
-    // Resolve body-level bindings, if there are any.
-    TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
-    Maybe<uint32_t> firstLexicalFrameSlot;
-    if (ModuleScope::Data* bindings = modulesc->bindings) {
-        BindingIter bi(*bindings);
-        for (; bi; bi++) {
-            if (!checkSlotLimits(bce, bi))
-                return false;
-
-            NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
-            if (!putNameInCache(bce, bi.name(), loc))
-                return false;
-
-            if (BindingKindIsLexical(bi.kind())) {
-                if (loc.kind() == NameLocation::Kind::FrameSlot && !firstLexicalFrameSlot)
-                    firstLexicalFrameSlot = Some(loc.frameSlot());
-
-                if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
-                    return false;
-            }
-        }
-
-        updateFrameFixedSlots(bce, bi);
-    } else {
-        nextFrameSlot_ = 0;
-    }
-
-    // Modules are toplevel, so any free names are global.
-    fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
-
-    // Put lexical frame slots in TDZ. Environment slots are poisoned during
-    // environment creation.
-    if (firstLexicalFrameSlot) {
-        if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd()))
-            return false;
-    }
-
-    // Create and intern the VM scope.
-    auto createScope = [modulesc](JSContext* cx, HandleScope enclosing) {
-        return ModuleScope::create(cx, modulesc->bindings, modulesc->module(), enclosing);
-    };
-    if (!internBodyScope(bce, createScope))
-        return false;
-
-    return checkEnvironmentChainLength(bce);
-}
-
-bool
-BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
-{
-    MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
-
-    if (!ensureCache(bce))
-        return false;
-
-    // 'with' make all accesses dynamic and unanalyzable.
-    fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
-
-    auto createScope = [](JSContext* cx, HandleScope enclosing) {
-        return WithScope::create(cx, enclosing);
-    };
-    if (!internScope(bce, createScope))
-        return false;
-
-    if (!bce->emitInternedScopeOp(index(), JSOP_ENTERWITH))
-        return false;
-
-    if (!appendScopeNote(bce))
-        return false;
-
-    return checkEnvironmentChainLength(bce);
-}
-
-bool
-BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
-{
-    // If we aren't leaving the scope due to a non-local jump (e.g., break),
-    // we must be the innermost scope.
-    MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
-
-    ScopeKind kind = scope(bce)->kind();
-    switch (kind) {
-      case ScopeKind::Lexical:
-      case ScopeKind::SimpleCatch:
-      case ScopeKind::Catch:
-        if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
-            return false;
-        break;
-
-      case ScopeKind::With:
-        if (!bce->emit1(JSOP_LEAVEWITH))
-            return false;
-        break;
-
-      case ScopeKind::ParameterExpressionVar:
-        MOZ_ASSERT(hasEnvironment());
-        if (!bce->emit1(JSOP_POPVARENV))
-            return false;
-        break;
-
-      case ScopeKind::Function:
-      case ScopeKind::FunctionBodyVar:
-      case ScopeKind::NamedLambda:
-      case ScopeKind::StrictNamedLambda:
-      case ScopeKind::Eval:
-      case ScopeKind::StrictEval:
-      case ScopeKind::Global:
-      case ScopeKind::NonSyntactic:
-      case ScopeKind::Module:
-        break;
-
-      case ScopeKind::WasmInstance:
-      case ScopeKind::WasmFunction:
-        MOZ_CRASH("No wasm function scopes in JS");
-    }
-
-    // Finish up the scope if we are leaving it in LIFO fashion.
-    if (!nonLocal) {
-        // Popping scopes due to non-local jumps generate additional scope
-        // notes. See NonLocalExitControl::prepareForNonLocalJump.
-        if (ScopeKindIsInBody(kind)) {
-            // The extra function var scope is never popped once it's pushed,
-            // so its scope note extends until the end of any possible code.
-            uint32_t offset = kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
-            bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
-        }
-    }
-
-    return true;
-}
-
-Maybe<MaybeCheckTDZ>
-BytecodeEmitter::TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name)
-{
-    if (!ensureCache(bce))
-        return Nothing();
-
-    CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
-    if (p)
-        return Some(p->value().wrapped);
-
-    MaybeCheckTDZ rv = CheckTDZ;
-    for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) {
-        if (it->cache_) {
-            if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) {
-                rv = p2->value();
-                break;
-            }
-        }
-    }
-
-    if (!cache_->add(p, name, rv)) {
-        ReportOutOfMemory(bce->cx);
-        return Nothing();
-    }
-
-    return Some(rv);
-}
-
-bool
-BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
-                                             MaybeCheckTDZ check)
-{
-    if (!ensureCache(bce))
-        return false;
-
-    CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
-    if (p) {
-        MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block.");
-        p->value() = check;
-    } else {
-        if (!cache_->add(p, name, check)) {
-            ReportOutOfMemory(bce->cx);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// Class for emitting bytecode for blocks like try-catch-finally.
-//
-// Usage: (check for the return value is omitted for simplicity)
-//
-//   `try { try_block } catch (ex) { catch_block }`
-//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
-//                         TryEmitter::ControlKind::Syntactic);
-//     tryCatch.emitTry();
-//     emit(try_block);
-//     tryCatch.emitCatch();
-//     emit(ex and catch_block); // use JSOP_EXCEPTION to get exception
-//     tryCatch.emitEnd();
-//
-//   `try { try_block } finally { finally_block }`
-//     TryEmitter tryCatch(this, TryEmitter::Kind::TryFinally,
-//                         TryEmitter::ControlKind::Syntactic);
-//     tryCatch.emitTry();
-//     emit(try_block);
-//     // finally_pos: The "{" character's position in the source code text.
-//     tryCatch.emitFinally(Some(finally_pos));
-//     emit(finally_block);
-//     tryCatch.emitEnd();
-//
-//   `try { try_block } catch (ex) {catch_block} finally { finally_block }`
-//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
-//                         TryEmitter::ControlKind::Syntactic);
-//     tryCatch.emitTry();
-//     emit(try_block);
-//     tryCatch.emitCatch();
-//     emit(ex and catch_block);
-//     tryCatch.emitFinally(Some(finally_pos));
-//     emit(finally_block);
-//     tryCatch.emitEnd();
-//
-class MOZ_STACK_CLASS TryEmitter
-{
-  public:
-    enum class Kind {
-        TryCatch,
-        TryCatchFinally,
-        TryFinally
-    };
-
-    // Syntactic try-catch-finally and internally used non-syntactic
-    // try-catch-finally behave differently for 2 points.
-    //
-    // The first one is whether TryFinallyControl is used or not.
-    // See the comment for `controlInfo_`.
-    //
-    // The second one is whether the catch and finally blocks handle the frame's
-    // return value.  For syntactic try-catch-finally, the bytecode marked with
-    // "*" are emitted to clear return value with `undefined` before the catch
-    // block and the finally block, and also to save/restore the return value
-    // before/after the finally block.
-    //
-    //     JSOP_TRY
-    //
-    //     try_body...
-    //
-    //     JSOP_GOSUB finally
-    //     JSOP_JUMPTARGET
-    //     JSOP_GOTO end:
-    //
-    //   catch:
-    //     JSOP_JUMPTARGET
-    //   * JSOP_UNDEFINED
-    //   * JSOP_SETRVAL
-    //
-    //     catch_body...
-    //
-    //     JSOP_GOSUB finally
-    //     JSOP_JUMPTARGET
-    //     JSOP_GOTO end
-    //
-    //   finally:
-    //     JSOP_JUMPTARGET
-    //   * JSOP_GETRVAL
-    //   * JSOP_UNDEFINED
-    //   * JSOP_SETRVAL
-    //
-    //     finally_body...
-    //
-    //   * JSOP_SETRVAL
-    //     JSOP_NOP
-    //
-    //   end:
-    //     JSOP_JUMPTARGET
-    //
-    // For syntactic try-catch-finally, Syntactic should be used.
-    // For non-syntactic try-catch-finally, NonSyntactic should be used.
-    enum class ControlKind {
-        Syntactic,
-        NonSyntactic
-    };
-
-  private:
-    BytecodeEmitter* bce_;
-    Kind kind_;
-    ControlKind controlKind_;
-
-    // Track jumps-over-catches and gosubs-to-finally for later fixup.
-    //
-    // When a finally block is active, non-local jumps (including
-    // jumps-over-catches) result in a GOSUB being written into the bytecode
-    // stream and fixed-up later.
-    //
-    // For non-syntactic try-catch-finally, all that handling is skipped.
-    // The non-syntactic try-catch-finally must:
-    //   * have only one catch block
-    //   * have JSOP_GOTO at the end of catch-block
-    //   * have no non-local-jump
-    //   * don't use finally block for normal completion of try-block and
-    //     catch-block
-    //
-    // Additionally, a finally block may be emitted for non-syntactic
-    // try-catch-finally, even if the kind is TryCatch, because GOSUBs are not
-    // emitted.
-    Maybe<TryFinallyControl> controlInfo_;
-
-    // The stack depth before emitting JSOP_TRY.
-    int depth_;
-
-    // The source note index for SRC_TRY.
-    unsigned noteIndex_;
-
-    // The offset after JSOP_TRY.
-    ptrdiff_t tryStart_;
-
-    // JSOP_JUMPTARGET after the entire try-catch-finally block.
-    JumpList catchAndFinallyJump_;
-
-    // The offset of JSOP_GOTO at the end of the try block.
-    JumpTarget tryEnd_;
-
-    // The offset of JSOP_JUMPTARGET at the beginning of the finally block.
-    JumpTarget finallyStart_;
-
-#ifdef DEBUG
-    // The state of this emitter.
-    //
-    // +-------+ emitTry +-----+   emitCatch +-------+      emitEnd  +-----+
-    // | Start |-------->| Try |-+---------->| Catch |-+->+--------->| End |
-    // +-------+         +-----+ |           +-------+ |  ^          +-----+
-    //                           |                     |  |
-    //                           |  +------------------+  +----+
-    //                           |  |                          |
-    //                           |  v emitFinally +---------+  |
-    //                           +->+------------>| Finally |--+
-    //                                            +---------+
-    enum class State {
-        // The initial state.
-        Start,
-
-        // After calling emitTry.
-        Try,
-
-        // After calling emitCatch.
-        Catch,
-
-        // After calling emitFinally.
-        Finally,
-
-        // After calling emitEnd.
-        End
-    };
-    State state_;
-#endif
-
-    bool hasCatch() const {
-        return kind_ == Kind::TryCatch || kind_ == Kind::TryCatchFinally;
-    }
-    bool hasFinally() const {
-        return kind_ == Kind::TryCatchFinally || kind_ == Kind::TryFinally;
-    }
-
-  public:
-    TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind)
-      : bce_(bce),
-        kind_(kind),
-        controlKind_(controlKind),
-        depth_(0),
-        noteIndex_(0),
-        tryStart_(0),
-        tryEnd_{}
-#ifdef DEBUG
-      , state_(State::Start)
-#endif
-    {
-        if (controlKind_ == ControlKind::Syntactic)
-            controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
-        finallyStart_.offset = 0;
-    }
-
-    // Emits JSOP_GOTO to the end of try-catch-finally.
-    // Used in `yield*`.
-    MOZ_MUST_USE bool emitJumpOverCatchAndFinally() {
-        if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
-            return false;
-        return true;
-    }
-
-    MOZ_MUST_USE bool emitTry() {
-        MOZ_ASSERT(state_ == State::Start);
-
-        // Since an exception can be thrown at any place inside the try block,
-        // we need to restore the stack and the scope chain before we transfer
-        // the control to the exception handler.
-        //
-        // For that we store in a try note associated with the catch or
-        // finally block the stack depth upon the try entry. The interpreter
-        // uses this depth to properly unwind the stack and the scope chain.
-        depth_ = bce_->stackDepth;
-
-        // Record the try location, then emit the try block.
-        if (!bce_->newSrcNote(SRC_TRY, &noteIndex_))
-            return false;
-        if (!bce_->emit1(JSOP_TRY))
-            return false;
-        tryStart_ = bce_->offset();
-
-#ifdef DEBUG
-        state_ = State::Try;
-#endif
-        return true;
-    }
-
-  private:
-    MOZ_MUST_USE bool emitTryEnd() {
-        MOZ_ASSERT(state_ == State::Try);
-        MOZ_ASSERT(depth_ == bce_->stackDepth);
-
-        // GOSUB to finally, if present.
-        if (hasFinally() && controlInfo_) {
-            if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
-                return false;
-        }
-
-        // Source note points to the jump at the end of the try block.
-        if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
-            return false;
-
-        // Emit jump over catch and/or finally.
-        if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
-            return false;
-
-        if (!bce_->emitJumpTarget(&tryEnd_))
-            return false;
-
-        return true;
-    }
-
-  public:
-    MOZ_MUST_USE bool emitCatch() {
-        MOZ_ASSERT(state_ == State::Try);
-        if (!emitTryEnd())
-            return false;
-
-        MOZ_ASSERT(bce_->stackDepth == depth_);
-
-        if (controlKind_ == ControlKind::Syntactic) {
-            // Clear the frame's return value that might have been set by the
-            // try block:
-            //
-            //   eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
-            if (!bce_->emit1(JSOP_UNDEFINED))
-                return false;
-            if (!bce_->emit1(JSOP_SETRVAL))
-                return false;
-        }
-
-#ifdef DEBUG
-        state_ = State::Catch;
-#endif
-        return true;
-    }
-
-  private:
-    MOZ_MUST_USE bool emitCatchEnd() {
-        MOZ_ASSERT(state_ == State::Catch);
-
-        if (!controlInfo_)
-            return true;
-
-        // gosub <finally>, if required.
-        if (hasFinally()) {
-            if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
-                return false;
-            MOZ_ASSERT(bce_->stackDepth == depth_);
-
-            // Jump over the finally block.
-            if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
-                return false;
-        }
-
-        return true;
-    }
-
-  public:
-    // If `finallyPos` is specified, it's an offset of the finally block's
-    // "{" character in the source code text, to improve line:column number in
-    // the error reporting.
-    // For non-syntactic try-catch-finally, `finallyPos` can be omitted.
-    MOZ_MUST_USE bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
-        // If we are using controlInfo_ (i.e., emitting a syntactic try
-        // blocks), we must have specified up front if there will be a finally
-        // close. For internal non-syntactic try blocks, like those emitted for
-        // yield* and IteratorClose inside for-of loops, we can emitFinally even
-        // without specifying up front, since the internal non-syntactic try
-        // blocks emit no GOSUBs.
-        if (!controlInfo_) {
-            if (kind_ == Kind::TryCatch)
-                kind_ = Kind::TryCatchFinally;
-        } else {
-            MOZ_ASSERT(hasFinally());
-        }
-
-        if (!hasCatch()) {
-            MOZ_ASSERT(state_ == State::Try);
-            if (!emitTryEnd())
-                return false;
-        } else {
-            MOZ_ASSERT(state_ == State::Catch);
-            if (!emitCatchEnd())
-                return false;
-        }
-
-        MOZ_ASSERT(bce_->stackDepth == depth_);
-
-        if (!bce_->emitJumpTarget(&finallyStart_))
-            return false;
-
-        if (controlInfo_) {
-            // Fix up the gosubs that might have been emitted before non-local
-            // jumps to the finally code.
-            bce_->patchJumpsToTarget(controlInfo_->gosubs, finallyStart_);
-
-            // Indicate that we're emitting a subroutine body.
-            controlInfo_->setEmittingSubroutine();
-        }
-        if (finallyPos) {
-            if (!bce_->updateSourceCoordNotes(finallyPos.value()))
-                return false;
-        }
-        if (!bce_->emit1(JSOP_FINALLY))
-            return false;
-
-        if (controlKind_ == ControlKind::Syntactic) {
-            if (!bce_->emit1(JSOP_GETRVAL))
-                return false;
-
-            // Clear the frame's return value to make break/continue return
-            // correct value even if there's no other statement before them:
-            //
-            //   eval("x: try { 1 } finally { break x; }"); // undefined, not 1
-            if (!bce_->emit1(JSOP_UNDEFINED))
-                return false;
-            if (!bce_->emit1(JSOP_SETRVAL))
-                return false;
-        }
-
-#ifdef DEBUG
-        state_ = State::Finally;
-#endif
-        return true;
-    }
-
-  private:
-    MOZ_MUST_USE bool emitFinallyEnd() {
-        MOZ_ASSERT(state_ == State::Finally);
-
-        if (controlKind_ == ControlKind::Syntactic) {
-            if (!bce_->emit1(JSOP_SETRVAL))
-                return false;
-        }
-
-        if (!bce_->emit1(JSOP_RETSUB))
-            return false;
-
-        bce_->hasTryFinally = true;
-        return true;
-    }
-
-  public:
-    MOZ_MUST_USE bool emitEnd() {
-        if (!hasFinally()) {
-            MOZ_ASSERT(state_ == State::Catch);
-            if (!emitCatchEnd())
-                return false;
-        } else {
-            MOZ_ASSERT(state_ == State::Finally);
-            if (!emitFinallyEnd())
-                return false;
-        }
-
-        MOZ_ASSERT(bce_->stackDepth == depth_);
-
-        // ReconstructPCStack needs a NOP here to mark the end of the last
-        // catch block.
-        if (!bce_->emit1(JSOP_NOP))
-            return false;
-
-        // Fix up the end-of-try/catch jumps to come here.
-        if (!bce_->emitJumpTargetAndPatch(catchAndFinallyJump_))
-            return false;
-
-        // Add the try note last, to let post-order give us the right ordering
-        // (first to last for a given nesting level, inner to outer by level).
-        if (hasCatch()) {
-            if (!bce_->tryNoteList.append(JSTRY_CATCH, depth_, tryStart_, tryEnd_.offset))
-                return false;
-        }
-
-        // If we've got a finally, mark try+catch region with additional
-        // trynote to catch exceptions (re)thrown from a catch block or
-        // for the try{}finally{} case.
-        if (hasFinally()) {
-            if (!bce_->tryNoteList.append(JSTRY_FINALLY, depth_, tryStart_, finallyStart_.offset))
-                return false;
-        }
-
-#ifdef DEBUG
-        state_ = State::End;
-#endif
-        return true;
-    }
-};
-
-// Class for emitting bytecode for blocks like if-then-else.
-//
-// This class can be used to emit single if-then-else block, or cascading
-// else-if blocks.
-//
-// Usage: (check for the return value is omitted for simplicity)
-//
-//   `if (cond) then_block`
-//     IfEmitter ifThen(this);
-//     emit(cond);
-//     ifThen.emitThen();
-//     emit(then_block);
-//     ifThen.emitEnd();
-//
-//   `if (cond) then_block else else_block`
-//     IfEmitter ifThenElse(this);
-//     emit(cond);
-//     ifThenElse.emitThenElse();
-//     emit(then_block);
-//     ifThenElse.emitElse();
-//     emit(else_block);
-//     ifThenElse.emitEnd();
-//
-//   `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4`
-//     IfEmitter ifThenElse(this);
-//     emit(c1);
-//     ifThenElse.emitThenElse();
-//     emit(b1);
-//     ifThenElse.emitElseIf();
-//     emit(c2);
-//     ifThenElse.emitThenElse();
-//     emit(b2);
-//     ifThenElse.emitElseIf();
-//     emit(c3);
-//     ifThenElse.emitThenElse();
-//     emit(b3);
-//     ifThenElse.emitElse();
-//     emit(b4);
-//     ifThenElse.emitEnd();
-//
-//   `cond ? then_expr : else_expr`
-//     IfEmitter condElse(this);
-//     emit(cond);
-//     condElse.emitCond();
-//     emit(then_block);
-//     condElse.emitElse();
-//     emit(else_block);
-//     condElse.emitEnd();
-//
-class MOZ_STACK_CLASS IfEmitter
-{
-  public:
-    // Whether the then-clause, the else-clause, or else-if condition may
-    // contain declaration or access to lexical variables, which means they
-    // should have their own TDZCheckCache.  Basically TDZCheckCache should be
-    // created for each basic block, which then-clause, else-clause, and
-    // else-if condition are, but for internally used branches which are
-    // known not to touch lexical variables we can skip creating TDZCheckCache
-    // for them.
-    //
-    // See the comment for TDZCheckCache class for more details.
-    enum class Kind {
-        // For syntactic branches (if, if-else, and conditional expression),
-        // which basically may contain declaration or accesses to lexical
-        // variables inside then-clause, else-clause, and else-if condition.
-        MayContainLexicalAccessInBranch,
-
-        // For internally used branches which don't touch lexical variables
-        // inside then-clause, else-clause, nor else-if condition.
-        NoLexicalAccessInBranch
-    };
-
-  private:
-    using TDZCheckCache = BytecodeEmitter::TDZCheckCache;
-
-    BytecodeEmitter* bce_;
-
-    // Jump around the then clause, to the beginning of the else clause.
-    JumpList jumpAroundThen_;
-
-    // Jump around the else clause, to the end of the entire branch.
-    JumpList jumpsAroundElse_;
-
-    // The stack depth before emitting the then block.
-    // Used for restoring stack depth before emitting the else block.
-    // Also used for assertion to make sure then and else blocks pushed the
-    // same number of values.
-    int32_t thenDepth_;
-
-    Kind kind_;
-    Maybe<TDZCheckCache> tdzCache_;
-
-#ifdef DEBUG
-    // The number of values pushed in the then and else blocks.
-    int32_t pushed_;
-    bool calculatedPushed_;
-
-    // The state of this emitter.
-    //
-    // +-------+   emitCond +------+ emitElse +------+        emitEnd +-----+
-    // | Start |-+--------->| Cond |--------->| Else |------>+------->| End |
-    // +-------+ |          +------+          +------+       ^        +-----+
-    //           |                                           |
-    //           v emitThen +------+                         |
-    //        +->+--------->| Then |------------------------>+
-    //        ^  |          +------+                         ^
-    //        |  |                                           |
-    //        |  |                                           +---+
-    //        |  |                                               |
-    //        |  | emitThenElse +----------+   emitElse +------+ |
-    //        |  +------------->| ThenElse |-+--------->| Else |-+
-    //        |                 +----------+ |          +------+
-    //        |                              |
-    //        |                              | emitElseIf +--------+
-    //        |                              +----------->| ElseIf |-+
-    //        |                                           +--------+ |
-    //        |                                                      |
-    //        +------------------------------------------------------+
-    enum class State {
-        // The initial state.
-        Start,
-
-        // After calling emitThen.
-        Then,
-
-        // After calling emitCond.
-        Cond,
-
-        // After calling emitThenElse.
-        ThenElse,
-
-        // After calling emitElse.
-        Else,
-
-        // After calling emitElseIf.
-        ElseIf,
-
-        // After calling emitEnd.
-        End
-    };
-    State state_;
-#endif
-
-  protected:
-    // For InternalIfEmitter.
-    IfEmitter(BytecodeEmitter* bce, Kind kind)
-      : bce_(bce)
-      , thenDepth_(0)
-      , kind_(kind)
-#ifdef DEBUG
-      , pushed_(0)
-      , calculatedPushed_(false)
-      , state_(State::Start)
-#endif
-    {}
-
-  public:
-    explicit IfEmitter(BytecodeEmitter* bce)
-      : IfEmitter(bce, Kind::MayContainLexicalAccessInBranch)
-    {}
-
-  private:
-    MOZ_MUST_USE bool emitIfInternal(SrcNoteType type) {
-        MOZ_ASSERT_IF(state_ == State::ElseIf, tdzCache_.isSome());
-        MOZ_ASSERT_IF(state_ != State::ElseIf, tdzCache_.isNothing());
-
-        // The end of TDZCheckCache for cond for else-if.
-        if (kind_ == Kind::MayContainLexicalAccessInBranch)
-            tdzCache_.reset();
-
-        // Emit an annotated branch-if-false around the then part.
-        if (!bce_->newSrcNote(type))
-            return false;
-        if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_))
-            return false;
-
-        // To restore stack depth in else part, save depth of the then part.
-#ifdef DEBUG
-        // If DEBUG, this is also necessary to calculate |pushed_|.
-        thenDepth_ = bce_->stackDepth;
-#else
-        if (type == SRC_COND || type == SRC_IF_ELSE)
-            thenDepth_ = bce_->stackDepth;
-#endif
-
-        // Enclose then-branch with TDZCheckCache.
-        if (kind_ == Kind::MayContainLexicalAccessInBranch)
-            tdzCache_.emplace(bce_);
-
-        return true;
-    }
-
-    void calculateOrCheckPushed() {
-#ifdef DEBUG
-        if (!calculatedPushed_) {
-            pushed_ = bce_->stackDepth - thenDepth_;
-            calculatedPushed_ = true;
-        } else {
-            MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
-        }
-#endif
-    }
-
-  public:
-    MOZ_MUST_USE bool emitThen() {
-        MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
-        if (!emitIfInternal(SRC_IF))
-            return false;
-
-#ifdef DEBUG
-        state_ = State::Then;
-#endif
-        return true;
-    }
-
-    MOZ_MUST_USE bool emitCond() {
-        MOZ_ASSERT(state_ == State::Start);
-        if (!emitIfInternal(SRC_COND))
-            return false;
-
-#ifdef DEBUG
-        state_ = State::Cond;
-#endif
-        return true;
-    }
-
-    MOZ_MUST_USE bool emitThenElse() {
-        MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
-        if (!emitIfInternal(SRC_IF_ELSE))
-            return false;
-
-#ifdef DEBUG
-        state_ = State::ThenElse;
-#endif
-        return true;
-    }
-
-  private:
-    MOZ_MUST_USE bool emitElseInternal() {
-        calculateOrCheckPushed();
-
-        // The end of TDZCheckCache for then-clause.
-        if (kind_ == Kind::MayContainLexicalAccessInBranch) {
-            MOZ_ASSERT(tdzCache_.isSome());
-            tdzCache_.reset();
-        }
-
-        // Emit a jump from the end of our then part around the else part. The
-        // patchJumpsToTarget call at the bottom of this function will fix up
-        // the offset with jumpsAroundElse value.
-        if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_))
-            return false;
-
-        // Ensure the branch-if-false comes here, then emit the else.
-        if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
-            return false;
-
-        // Clear jumpAroundThen_ offset, to tell emitEnd there was an else part.
-        jumpAroundThen_ = JumpList();
-
-        // Restore stack depth of the then part.
-        bce_->stackDepth = thenDepth_;
-#ifdef DEBUG
-        state_ = State::Else;
-#endif
-        return true;
-    }
-
-  public:
-    MOZ_MUST_USE bool emitElse() {
-        MOZ_ASSERT(state_ == State::ThenElse || state_ == State::Cond);
-
-        if (!emitElseInternal())
-            return false;
-
-        // Enclose else-branch with TDZCheckCache.
-        if (kind_ == Kind::MayContainLexicalAccessInBranch)
-            tdzCache_.emplace(bce_);
-
-#ifdef DEBUG
-        state_ = State::Else;
-#endif
-        return true;
-    }
-
-    MOZ_MUST_USE bool emitElseIf() {
-        MOZ_ASSERT(state_ == State::ThenElse);
-
-        if (!emitElseInternal())
-            return false;
-
-        // Enclose cond for else-if with TDZCheckCache.
-        if (kind_ == Kind::MayContainLexicalAccessInBranch)
-            tdzCache_.emplace(bce_);
-
-#ifdef DEBUG
-        state_ = State::ElseIf;
-#endif
-        return true;
-    }
-
-    MOZ_MUST_USE bool emitEnd() {
-        MOZ_ASSERT(state_ == State::Then || state_ == State::Else);
-        // If there was an else part for the last branch, jumpAroundThen_ is
-        // already fixed up when emitting the else part.
-        MOZ_ASSERT_IF(state_ == State::Then, jumpAroundThen_.offset != -1);
-        MOZ_ASSERT_IF(state_ == State::Else, jumpAroundThen_.offset == -1);
-
-        // The end of TDZCheckCache for then or else-clause.
-        if (kind_ == Kind::MayContainLexicalAccessInBranch) {
-            MOZ_ASSERT(tdzCache_.isSome());
-            tdzCache_.reset();
-        }
-
-        calculateOrCheckPushed();
-
-        if (jumpAroundThen_.offset != -1) {
-            // No else part for the last branch, fixup the branch-if-false to
-            // come here.
-            if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
-                return false;
-        }
-
-        // Patch all the jumps around else parts.
-        if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
-            return false;
-
-#ifdef DEBUG
-        state_ = State::End;
-#endif
-        return true;
-    }
-
-#ifdef DEBUG
-    // Returns the number of values pushed onto the value stack inside
-    // `then_block` and `else_block`.
-    // Can be used in assertion after emitting if-then-else.
-    int32_t pushed() const {
-        return pushed_;
-    }
-
-    // Returns the number of values popped onto the value stack inside
-    // `then_block` and `else_block`.
-    // Can be used in assertion after emitting if-then-else.
-    int32_t popped() const {
-        return -pushed_;
-    }
-#endif
-};
-
-// Class for emitting bytecode for blocks like if-then-else which doesn't touch
-// lexical variables.
-//
-// See the comments above NoLexicalAccessInBranch for more details when to use
-// this instead of IfEmitter.
-class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter
-{
-  public:
-    explicit InternalIfEmitter(BytecodeEmitter* bce)
-      : IfEmitter(bce, Kind::NoLexicalAccessInBranch)
-    {}
-};
-
-class ForOfLoopControl : public LoopControl
-{
-    using EmitterScope = BytecodeEmitter::EmitterScope;
-
-    // The stack depth of the iterator.
-    int32_t iterDepth_;
-
-    // for-of loops, when throwing from non-iterator code (i.e. from the body
-    // or from evaluating the LHS of the loop condition), need to call
-    // IteratorClose.  This is done by enclosing non-iterator code with
-    // try-catch and call IteratorClose in `catch` block.
-    // If IteratorClose itself throws, we must not re-call IteratorClose. Since
-    // non-local jumps like break and return call IteratorClose, whenever a
-    // non-local jump is emitted, we must tell catch block not to perform
-    // IteratorClose.
-    //
-    //   for (x of y) {
-    //     // Operations for iterator (IteratorNext etc) are outside of
-    //     // try-block.
-    //     try {
-    //       ...
-    //       if (...) {
-    //         // Before non-local jump, clear iterator on the stack to tell
-    //         // catch block not to perform IteratorClose.
-    //         tmpIterator = iterator;
-    //         iterator = undefined;
-    //         IteratorClose(tmpIterator, { break });
-    //         break;
-    //       }
-    //       ...
-    //     } catch (e) {
-    //       // Just throw again when iterator is cleared by non-local jump.
-    //       if (iterator === undefined)
-    //         throw e;
-    //       IteratorClose(iterator, { throw, e });
-    //     }
-    //   }
-    Maybe<TryEmitter> tryCatch_;
-
-    // Used to track if any yields were emitted between calls to to
-    // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
-    uint32_t numYieldsAtBeginCodeNeedingIterClose_;
-
-    bool allowSelfHosted_;
-
-    IteratorKind iterKind_;
-
-  public:
-    ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
-                     IteratorKind iterKind)
-      : LoopControl(bce, StatementKind::ForOfLoop),
-        iterDepth_(iterDepth),
-        numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
-        allowSelfHosted_(allowSelfHosted),
-        iterKind_(iterKind)
-    {
-    }
-
-    bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
-        tryCatch_.emplace(bce, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
-
-        if (!tryCatch_->emitTry())
-            return false;
-
-        MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
-        numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
-
-        return true;
-    }
-
-    bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
-        if (!tryCatch_->emitCatch())              // ITER ...
-            return false;
-
-        if (!bce->emit1(JSOP_EXCEPTION))          // ITER ... EXCEPTION
-            return false;
-        unsigned slotFromTop = bce->stackDepth - iterDepth_;
-        if (!bce->emitDupAt(slotFromTop))         // ITER ... EXCEPTION ITER
-            return false;
-
-        // If ITER is undefined, it means the exception is thrown by
-        // IteratorClose for non-local jump, and we should't perform
-        // IteratorClose again here.
-        if (!bce->emit1(JSOP_UNDEFINED))          // ITER ... EXCEPTION ITER UNDEF
-            return false;
-        if (!bce->emit1(JSOP_STRICTNE))           // ITER ... EXCEPTION NE
-            return false;
-
-        InternalIfEmitter ifIteratorIsNotClosed(bce);
-        if (!ifIteratorIsNotClosed.emitThen())    // ITER ... EXCEPTION
-            return false;
-
-        MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
-        if (!bce->emitDupAt(slotFromTop))         // ITER ... EXCEPTION ITER
-            return false;
-        if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw))
-            return false;                         // ITER ... EXCEPTION
-
-        if (!ifIteratorIsNotClosed.emitEnd())     // ITER ... EXCEPTION
-            return false;
-
-        if (!bce->emit1(JSOP_THROW))              // ITER ...
-            return false;
-
-        // If any yields were emitted, then this for-of loop is inside a star
-        // generator and must handle the case of Generator.return. Like in
-        // yield*, it is handled with a finally block.
-        uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
-        if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
-            if (!tryCatch_->emitFinally())
-                return false;
-
-            InternalIfEmitter ifGeneratorClosing(bce);
-            if (!bce->emit1(JSOP_ISGENCLOSING))   // ITER ... FTYPE FVALUE CLOSING
-                return false;
-            if (!ifGeneratorClosing.emitThen())   // ITER ... FTYPE FVALUE
-                return false;
-            if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
-                return false;
-            if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal))
-                return false;                     // ITER ... FTYPE FVALUE
-            if (!ifGeneratorClosing.emitEnd())    // ITER ... FTYPE FVALUE
-                return false;
-        }
-
-        if (!tryCatch_->emitEnd())
-            return false;
-
-        tryCatch_.reset();
-        numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
-
-        return true;
-    }
-
-    bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
-                                           CompletionKind completionKind = CompletionKind::Normal) {
-        return emitIteratorCloseInScope(bce,  *bce->innermostEmitterScope(), completionKind);
-    }
-
-    bool emitIteratorCloseInScope(BytecodeEmitter* bce,
-                                  EmitterScope& currentScope,
-                                  CompletionKind completionKind = CompletionKind::Normal) {
-        ptrdiff_t start = bce->offset();
-        if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
-                                           allowSelfHosted_))
-        {
-            return false;
-        }
-        ptrdiff_t end = bce->offset();
-        return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
-    }
-
-    bool emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
-                                             EmitterScope& currentScope,
-                                             bool isTarget) {
-        // Pop unnecessary value from the stack.  Effectively this means
-        // leaving try-catch block.  However, the performing IteratorClose can
-        // reach the depth for try-catch, and effectively re-enter the
-        // try-catch block.
-        if (!bce->emit1(JSOP_POP))                        // NEXT ITER
-            return false;
-
-        // Pop the iterator's next method.
-        if (!bce->emit1(JSOP_SWAP))                       // ITER NEXT
-            return false;
-        if (!bce->emit1(JSOP_POP))                        // ITER
-            return false;
-
-        // Clear ITER slot on the stack to tell catch block to avoid performing
-        // IteratorClose again.
-        if (!bce->emit1(JSOP_UNDEFINED))                  // ITER UNDEF
-            return false;
-        if (!bce->emit1(JSOP_SWAP))                       // UNDEF ITER
-            return false;
-
-        if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) // UNDEF
-            return false;
-
-        if (isTarget) {
-            // At the level of the target block, there's bytecode after the
-            // loop that will pop the next method, the iterator, and the
-            // value, so push two undefineds to balance the stack.
-            if (!bce->emit1(JSOP_UNDEFINED))              // UNDEF UNDEF
-                return false;
-            if (!bce->emit1(JSOP_UNDEFINED))              // UNDEF UNDEF UNDEF
-                return false;
-        } else {
-            if (!bce->emit1(JSOP_POP))                    //
-                return false;
-        }
-
-        return true;
-    }
-};
-
-
 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
                                  SharedContext* sc, HandleScript script,
                                  Handle<LazyScript*> lazyScript,
                                  uint32_t lineNum, EmitterMode emitterMode)
   : sc(sc),
     cx(sc->context),
     parent(parent),
     script(cx, script),
@@ -2741,37 +317,16 @@ BytecodeEmitter::emitJumpTarget(JumpTarg
 
     target->offset = off;
     current->lastTarget.offset = off;
     if (!emit1(JSOP_JUMPTARGET))
         return false;
     return true;
 }
 
-void
-JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset)
-{
-    SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset);
-    offset = jumpOffset;
-}
-
-void
-JumpList::patchAll(jsbytecode* code, JumpTarget target)
-{
-    ptrdiff_t delta;
-    for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) {
-        jsbytecode* pc = &code[jumpOffset];
-        MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL);
-        delta = GET_JUMP_OFFSET(pc);
-        MOZ_ASSERT(delta < 0);
-        ptrdiff_t span = target.offset - jumpOffset;
-        SET_JUMP_OFFSET(pc, span);
-    }
-}
-
 bool
 BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump)
 {
     ptrdiff_t offset;
     if (!emitCheck(5, &offset))
         return false;
 
     jsbytecode* code = this->code(offset);
@@ -3061,42 +616,42 @@ class NonLocalExitControl
     BytecodeEmitter* bce_;
     const uint32_t savedScopeNoteIndex_;
     const int savedDepth_;
     uint32_t openScopeNoteIndex_;
     Kind kind_;
 
     NonLocalExitControl(const NonLocalExitControl&) = delete;
 
-    MOZ_MUST_USE bool leaveScope(BytecodeEmitter::EmitterScope* scope);
+    MOZ_MUST_USE bool leaveScope(EmitterScope* scope);
 
   public:
     NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
       : bce_(bce),
         savedScopeNoteIndex_(bce->scopeNoteList.length()),
         savedDepth_(bce->stackDepth),
         openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
         kind_(kind)
     { }
 
     ~NonLocalExitControl() {
         for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length(); n++)
             bce_->scopeNoteList.recordEnd(n, bce_->offset(), bce_->inPrologue());
         bce_->stackDepth = savedDepth_;
     }
 
-    MOZ_MUST_USE bool prepareForNonLocalJump(BytecodeEmitter::NestableControl* target);
+    MOZ_MUST_USE bool prepareForNonLocalJump(NestableControl* target);
 
     MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
         return prepareForNonLocalJump(nullptr);
     }
 };
 
 bool
-NonLocalExitControl::leaveScope(BytecodeEmitter::EmitterScope* es)
+NonLocalExitControl::leaveScope(EmitterScope* es)
 {
     if (!es->leave(bce_, /* nonLocal = */ true))
         return false;
 
     // As we pop each scope due to the non-local jump, emit notes that
     // record the extent of the enclosing scope. These notes will have
     // their ends recorded in ~NonLocalExitControl().
     uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
@@ -3109,21 +664,18 @@ NonLocalExitControl::leaveScope(Bytecode
 
     return true;
 }
 
 /*
  * Emit additional bytecode(s) for non-local jumps.
  */
 bool
-NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
-{
-    using NestableControl = BytecodeEmitter::NestableControl;
-    using EmitterScope = BytecodeEmitter::EmitterScope;
-
+NonLocalExitControl::prepareForNonLocalJump(NestableControl* target)
+{
     EmitterScope* es = bce_->innermostEmitterScope();
     int npops = 0;
 
     AutoCheckUnstableEmitterScope cues(bce_);
 
     // For 'continue', 'break', and 'return' statements, emit IteratorClose
     // bytecode inline. 'continue' statements do not call IteratorClose for
     // the loop they are continuing.
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -9,16 +9,17 @@
 #ifndef frontend_BytecodeEmitter_h
 #define frontend_BytecodeEmitter_h
 
 #include "mozilla/Attributes.h"
 
 #include "ds/InlineTable.h"
 #include "frontend/BCEParserHandle.h"
 #include "frontend/EitherParser.h"
+#include "frontend/JumpList.h"
 #include "frontend/SharedContext.h"
 #include "frontend/SourceNotes.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/Interpreter.h"
 #include "vm/Iteration.h"
 #include "vm/JSContext.h"
 #include "vm/JSScript.h"
 
@@ -103,89 +104,34 @@ struct CGYieldAndAwaitOffsetList {
     void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
 };
 
 // Have a few inline elements, so as to avoid heap allocation for tiny
 // sequences.  See bug 1390526.
 typedef Vector<jsbytecode, 64> BytecodeVector;
 typedef Vector<jssrcnote, 64> SrcNotesVector;
 
-// Linked list of jump instructions that need to be patched. The linked list is
-// stored in the bytes of the incomplete bytecode that will be patched, so no
-// extra memory is needed, and patching the instructions destroys the list.
-//
-// Example:
-//
-//     JumpList brList;
-//     if (!emitJump(JSOP_IFEQ, &brList))
-//         return false;
-//     ...
-//     JumpTarget label;
-//     if (!emitJumpTarget(&label))
-//         return false;
-//     ...
-//     if (!emitJump(JSOP_GOTO, &brList))
-//         return false;
-//     ...
-//     patchJumpsToTarget(brList, label);
-//
-//                 +-> -1
-//                 |
-//                 |
-//    ifeq ..   <+ +                +-+   ifeq ..
-//    ..         |                  |     ..
-//  label:       |                  +-> label:
-//    jumptarget |                  |     jumptarget
-//    ..         |                  |     ..
-//    goto .. <+ +                  +-+   goto .. <+
-//             |                                   |
-//             |                                   |
-//             +                                   +
-//           brList                              brList
-//
-//       |                                  ^
-//       +------- patchJumpsToTarget -------+
-//
-
-// Offset of a jump target instruction, used for patching jump instructions.
-struct JumpTarget {
-    ptrdiff_t offset;
-};
-
-struct JumpList {
-    // -1 is used to mark the end of jump lists.
-    JumpList() : offset(-1) {}
-    ptrdiff_t offset;
-
-    // Add a jump instruction to the list.
-    void push(jsbytecode* code, ptrdiff_t jumpOffset);
-
-    // Patch all jump instructions in this list to jump to `target`.  This
-    // clobbers the list.
-    void patchAll(jsbytecode* code, JumpTarget target);
-};
-
 // Used to control whether JSOP_CALL_IGNORES_RV is emitted for function calls.
 enum class ValueUsage {
     // Assume the value of the current expression may be used. This is always
     // correct but prohibits JSOP_CALL_IGNORES_RV.
     WantValue,
 
     // Pass this when emitting an expression if the expression's value is
     // definitely unused by later instructions. You must make sure the next
     // instruction is JSOP_POP, a jump to a JSOP_POP, or something similar.
     IgnoreValue
 };
 
+class EmitterScope;
+class NestableControl;
+class TDZCheckCache;
+
 struct MOZ_STACK_CLASS BytecodeEmitter
 {
-    class TDZCheckCache;
-    class NestableControl;
-    class EmitterScope;
-
     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
 
     JSContext* const cx;
 
     BytecodeEmitter* const parent;  /* enclosing function or global context */
 
     Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
 
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/EmitterScope.cpp
@@ -0,0 +1,1060 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "frontend/EmitterScope.h"
+
+#include "frontend/BytecodeEmitter.h"
+#include "frontend/TDZCheckCache.h"
+
+using namespace js;
+using namespace js::frontend;
+
+using mozilla::DebugOnly;
+using mozilla::Maybe;
+using mozilla::Nothing;
+using mozilla::Some;
+
+EmitterScope::EmitterScope(BytecodeEmitter* bce)
+  : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
+    nameCache_(bce->cx->frontendCollectionPool()),
+    hasEnvironment_(false),
+    environmentChainLength_(0),
+    nextFrameSlot_(0),
+    scopeIndex_(ScopeNote::NoScopeIndex),
+    noteIndex_(ScopeNote::NoScopeNoteIndex)
+{}
+
+static inline void
+MarkAllBindingsClosedOver(LexicalScope::Data& data)
+{
+    TrailingNamesArray& names = data.trailingNames;
+    for (uint32_t i = 0; i < data.length; i++)
+        names[i] = BindingName(names[i].name(), true);
+}
+
+bool
+EmitterScope::ensureCache(BytecodeEmitter* bce)
+{
+    return nameCache_.acquire(bce->cx);
+}
+
+template <typename BindingIter>
+bool
+EmitterScope::checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi)
+{
+    if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
+        bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
+    {
+        bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
+        return false;
+    }
+    return true;
+}
+
+bool
+EmitterScope::checkEnvironmentChainLength(BytecodeEmitter* bce)
+{
+    uint32_t hops;
+    if (EmitterScope* emitterScope = enclosing(&bce))
+        hops = emitterScope->environmentChainLength_;
+    else
+        hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
+
+    if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
+        bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
+        return false;
+    }
+
+    environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
+    return true;
+}
+
+void
+EmitterScope::updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi)
+{
+    nextFrameSlot_ = bi.nextFrameSlot();
+    if (nextFrameSlot_ > bce->maxFixedSlots)
+        bce->maxFixedSlots = nextFrameSlot_;
+    MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&
+                  (bce->sc->asFunctionBox()->isGenerator() ||
+                   bce->sc->asFunctionBox()->isAsync()),
+                  bce->maxFixedSlots == 0);
+}
+
+bool
+EmitterScope::putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation lo