Merge inbound to mozilla-central a=merge
authorCoroiu Cristina <ccoroiu@mozilla.com>
Fri, 28 Sep 2018 00:36:46 +0300
changeset 438592 be037b5b6327f423a45c50837de07bae9522bd9a
parent 438591 e1d012b989adf43f12c24cdb20e6eb5c10299774 (current diff)
parent 438530 7c8d290c3a42428238bbdda98707e9736fdfabfe (diff)
child 438593 3c8df5d50089a3e4d03a31d57e6a7fdbcfbd871f
child 438633 fafd4850a424d0ef3495b6878be8ec83fbae1637
child 438637 7fa93a38b8bbf23952ee4598b40eedde8b51ffa9
push id108345
push userccoroiu@mozilla.com
push dateThu, 27 Sep 2018 21:43:19 +0000
treeherdermozilla-inbound@3c8df5d50089 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
be037b5b6327 / 64.0a1 / 20180927220034 / files
nightly linux64
be037b5b6327 / 64.0a1 / 20180927220034 / files
nightly mac
be037b5b6327 / 64.0a1 / 20180927220034 / files
nightly win32
be037b5b6327 / 64.0a1 / 20180927220034 / files
nightly win64
be037b5b6327 / 64.0a1 / 20180927220034 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central a=merge
media/libyuv/update.py
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js
@@ -7,26 +7,21 @@ const {UrlClassifierTestUtils} = ChromeU
 XPCOMUtils.defineLazyServiceGetter(Services, "cookies",
                                    "@mozilla.org/cookieService;1",
                                    "nsICookieService");
 XPCOMUtils.defineLazyServiceGetter(Services, "cookiemgr",
                                    "@mozilla.org/cookiemanager;1",
                                    "nsICookieManager");
 
 function restore_prefs() {
-  Services.prefs.clearUserPref("browser.contentblocking.enabled");
-  Services.prefs.clearUserPref("browser.contentblocking.ui.enabled");
   Services.prefs.clearUserPref("network.cookie.cookieBehavior");
   Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
 }
 registerCleanupFunction(restore_prefs);
 
-Services.prefs.setBoolPref("browser.contentblocking.enabled", true);
-Services.prefs.setBoolPref("browser.contentblocking.ui.enabled", true);
-
 async function fake_profile_change() {
   await new Promise(resolve => {
     Services.obs.addObserver(function waitForDBClose() {
       Services.obs.removeObserver(waitForDBClose, "cookie-db-closed");
       resolve();
     }, "cookie-db-closed");
     Services.cookies.QueryInterface(Ci.nsIObserver).observe(null, "profile-before-change", "shutdown-persist");
   });
new file mode 100644
--- /dev/null
+++ b/build/build-clang/aarch64-vastart-checking.patch
@@ -0,0 +1,16 @@
+AArch64 Windows uses a five-argument __va_start, just like ARM.
+
+https://bugs.llvm.org/show_bug.cgi?id=39090
+
+diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
+index 22483f8..53d9cb2 100644
+--- a/clang/lib/Sema/SemaChecking.cpp
++++ b/clang/lib/Sema/SemaChecking.cpp
+@@ -917,6 +917,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
+     switch (Context.getTargetInfo().getTriple().getArch()) {
+     case llvm::Triple::arm:
+     case llvm::Triple::thumb:
++    case llvm::Triple::aarch64:
+       if (SemaBuiltinVAStartARMMicrosoft(TheCall))
+         return ExprError();
+       break;
--- a/build/build-clang/clang-win32-st-an.json
+++ b/build/build-clang/clang-win32-st-an.json
@@ -11,11 +11,12 @@
     "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
     "python_path": "c:/mozilla-build/python/python.exe",
     "cc": "cl.exe",
     "cxx": "cl.exe",
     "patches": [
       "r318309.patch",
       "r320462.patch",
       "msvc-host-x64.patch",
+      "aarch64-vastart-checking.patch",
       "loosen-msvc-detection.patch"
     ]
 }
--- a/build/build-clang/clang-win64-st-an.json
+++ b/build/build-clang/clang-win64-st-an.json
@@ -13,11 +13,12 @@
     "cc": "cl.exe",
     "cxx": "cl.exe",
     "ml": "ml64.exe",
     "patches": [
       "r318309.patch",
       "r320462.patch",
       "r327876.patch",
       "loosen-msvc-detection.patch",
+      "aarch64-vastart-checking.patch",
       "fflush-before-unlocking.patch"
     ]
 }
--- a/build/build-clang/clang-win64.json
+++ b/build/build-clang/clang-win64.json
@@ -13,11 +13,12 @@
     "cc": "cl.exe",
     "cxx": "cl.exe",
     "ml": "ml64.exe",
     "patches": [
       "workaround-issue38586.patch",
       "r342649-hotpatch-8-byte-nops.patch",
       "r342652-unpoison-thread-stacks.patch",
       "r343123-pin-asan-dll.patch",
+      "aarch64-vastart-checking.patch",
       "loosen-msvc-detection.patch"
     ]
 }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7262,17 +7262,30 @@ class CGCallGenerator(CGThing):
 
         # Build up our actual call
         self.cgRoot = CGList([])
 
         call = CGGeneric(nativeMethodName)
         if not static:
             call = CGWrapper(call, pre="%s->" % object)
         call = CGList([call, CGWrapper(args, pre="(", post=")")])
-        if resultConversion is not None:
+        if ((returnType is None or returnType.isVoid() or
+             resultOutParam is not None) and
+            # This check for TreeBoxObject is here due to bug 1434641.  Once
+            # nsITreeBoxObject is gone, it can go away.
+            descriptor.name != "TreeBoxObject"):
+            assert resultConversion is None
+            call = CGList([
+                CGWrapper(
+                    call,
+                    pre=("// NOTE: This assert does NOT call the function.\n"
+                         "static_assert(mozilla::IsVoid<decltype("),
+                    post=')>::value, "Should be returning void here");'),
+                call], "\n")
+        elif resultConversion is not None:
             call = CGList([resultConversion, CGWrapper(call, pre="(", post=")")])
         if resultVar is None and result is not None:
             needResultDecl = True
             resultVar = "result"
 
         if needResultDecl:
             if resultRooter is not None:
                 self.cgRoot.prepend(resultRooter)
@@ -14041,16 +14054,17 @@ class CGBindingRoot(CGThing):
         # Do codegen for all the enums
         enums = config.getEnums(webIDLFile)
         cgthings.extend(CGEnum(e) for e in enums)
 
         hasCode = (descriptors or callbackDescriptors or dictionaries or
                    callbacks)
         bindingHeaders["mozilla/dom/BindingUtils.h"] = hasCode
         bindingHeaders["mozilla/OwningNonNull.h"] = hasCode
+        bindingHeaders["mozilla/TypeTraits.h"] = hasCode
         bindingHeaders["mozilla/dom/BindingDeclarations.h"] = (
             not hasCode and enums)
 
         bindingHeaders["WrapperFactory.h"] = descriptors
         bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
         bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries  # AutoJSAPI
         # Ensure we see our enums in the generated .cpp file, for the ToJSValue
         # method body.  Also ensure that we see jsapi.h.
--- a/dom/svg/SVGFEImageElement.cpp
+++ b/dom/svg/SVGFEImageElement.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/SVGFEImageElementBinding.h"
 #include "mozilla/dom/SVGFilterElement.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 #include "nsContentUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsSVGUtils.h"
 #include "nsNetUtil.h"
+#include "SVGObserverUtils.h"
 #include "imgIContainer.h"
 #include "gfx2DGlue.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEImage)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
@@ -351,27 +352,19 @@ SVGFEImageElement::Notify(imgIRequest* a
     aRequest->GetImage(getter_AddRefs(container));
     MOZ_ASSERT(container, "who sent the notification then?");
     container->StartDecoding(imgIContainer::FLAG_NONE);
   }
 
   if (aType == imgINotificationObserver::LOAD_COMPLETE ||
       aType == imgINotificationObserver::FRAME_UPDATE ||
       aType == imgINotificationObserver::SIZE_AVAILABLE) {
-    Invalidate();
+    if (GetParent() && GetParent()->IsSVGElement(nsGkAtoms::filter)) {
+      SVGObserverUtils::InvalidateDirectRenderingObservers(
+        static_cast<SVGFilterElement*>(GetParent()));
+    }
   }
 
   return rv;
 }
 
-//----------------------------------------------------------------------
-// helper methods
-
-void
-SVGFEImageElement::Invalidate()
-{
-  if (GetParent() && GetParent()->IsSVGElement(nsGkAtoms::filter)) {
-    static_cast<SVGFilterElement*>(GetParent())->Invalidate();
-  }
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/svg/SVGFEImageElement.h
+++ b/dom/svg/SVGFEImageElement.h
@@ -71,19 +71,16 @@ public:
 
   void MaybeLoadSVGImage();
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> Href();
   already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
 
 private:
-  // Invalidate users of the filter containing this element.
-  void Invalidate();
-
   nsresult LoadSVGImage(bool aForce, bool aNotify);
 
 protected:
   virtual bool ProducesSRGB() override { return true; }
 
   virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override;
   virtual StringAttributesInfo GetStringInfo() override;
 
--- a/dom/svg/SVGFilterElement.cpp
+++ b/dom/svg/SVGFilterElement.cpp
@@ -132,33 +132,16 @@ SVGFilterElement::IsAttributeMapped(cons
     sMarkersMap,
     sTextContentElementsMap,
     sViewportsMap
   };
   return FindAttributeDependence(name, map) ||
     SVGFilterElementBase::IsAttributeMapped(name);
 }
 
-void
-SVGFilterElement::Invalidate()
-{
-  nsAutoTObserverArray<nsIMutationObserver*, 1> *observers = GetMutationObservers();
-
-  if (observers && !observers->IsEmpty()) {
-    nsAutoTObserverArray<nsIMutationObserver*, 1>::ForwardIterator iter(*observers);
-    while (iter.HasMore()) {
-      nsCOMPtr<nsIMutationObserver> obs(iter.GetNext());
-      RefPtr<SVGFilterObserver> filter = do_QueryObject(obs);
-      if (filter) {
-        filter->Invalidate();
-      }
-    }
-  }
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ bool
 SVGFilterElement::HasValidDimensions() const
 {
   return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
            mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
--- a/dom/svg/SVGFilterElement.h
+++ b/dom/svg/SVGFilterElement.h
@@ -36,19 +36,16 @@ protected:
   explicit SVGFilterElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIContent
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
 
-  // Invalidate users of this filter
-  void Invalidate();
-
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Height();
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -902,38 +902,38 @@ Grouper::PaintContainerItem(DIGroup* aGr
       aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext, aRecorder);
       aContext->GetDrawTarget()->PopLayer();
       GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey());
       aContext->GetDrawTarget()->FlushItem(aItemBounds);
       break;
     }
     case DisplayItemType::TYPE_MASK: {
       GP("Paint Mask\n");
-      auto maskItem = static_cast<nsDisplayMask*>(aItem);
+      auto maskItem = static_cast<nsDisplayMasksAndClipPaths*>(aItem);
       maskItem->SetPaintRect(maskItem->GetClippedBounds(mDisplayListBuilder));
       if (maskItem->IsValidMask()) {
         maskItem->PaintWithContentsPaintCallback(mDisplayListBuilder, aContext, [&] {
           GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey());
           aContext->GetDrawTarget()->FlushItem(aItemBounds);
           aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext, aRecorder);
           GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey());
           });
         aContext->GetDrawTarget()->FlushItem(aItemBounds);
       }
       break;
     }
     case DisplayItemType::TYPE_FILTER: {
       GP("Paint Filter\n");
-      // We don't currently support doing invalidation inside nsDisplayFilter
+      // We don't currently support doing invalidation inside nsDisplayFilters
       // for now just paint it as a single item
       BlobItemData* data = GetBlobItemDataForGroup(aItem, aGroup);
       if (data->mLayerManager->GetRoot()) {
         data->mLayerManager->BeginTransaction();
-        static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(mDisplayListBuilder,
-                                                           aContext, data->mLayerManager);
+        static_cast<nsDisplayFilters*>(aItem)->PaintAsLayer(mDisplayListBuilder,
+                                                            aContext, data->mLayerManager);
         if (data->mLayerManager->InTransaction()) {
           data->mLayerManager->AbortTransaction();
         }
         aContext->GetDrawTarget()->FlushItem(aItemBounds);
       }
       break;
     }
 
@@ -1721,33 +1721,34 @@ PaintItemByDrawTarget(nsDisplayItem* aIt
   bool isInvalidated = false;
   aDT->ClearRect(aImageRect.ToUnknownRect());
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT);
   MOZ_ASSERT(context);
 
   switch (aItem->GetType()) {
   case DisplayItemType::TYPE_MASK:
     context->SetMatrix(context->CurrentMatrix().PreScale(aScale.width, aScale.height).PreTranslate(-aOffset.x, -aOffset.y));
-    static_cast<nsDisplayMask*>(aItem)->PaintMask(aDisplayListBuilder, context, &isInvalidated);
+    static_cast<nsDisplayMasksAndClipPaths*>(aItem)->
+      PaintMask(aDisplayListBuilder, context, &isInvalidated);
     break;
   case DisplayItemType::TYPE_SVG_WRAPPER:
     {
       context->SetMatrix(context->CurrentMatrix().PreTranslate(-aOffset.x, -aOffset.y));
       isInvalidated = PaintByLayer(aItem, aDisplayListBuilder, aManager, context, aScale, [&]() {
         aManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aDisplayListBuilder);
       });
       break;
     }
 
   case DisplayItemType::TYPE_FILTER:
     {
       context->SetMatrix(context->CurrentMatrix().PreTranslate(-aOffset.x, -aOffset.y));
       isInvalidated = PaintByLayer(aItem, aDisplayListBuilder, aManager, context, aScale, [&]() {
-        static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aDisplayListBuilder,
-                                                           context, aManager);
+        static_cast<nsDisplayFilters*>(aItem)->PaintAsLayer(aDisplayListBuilder,
+                                                            context, aManager);
       });
       break;
     }
 
   default:
     context->SetMatrix(context->CurrentMatrix().PreScale(aScale.width, aScale.height).PreTranslate(-aOffset.x, -aOffset.y));
     if (aDisplayListBuilder->IsPaintingToWindow()) {
       aItem->Frame()->AddStateBits(NS_FRAME_PAINTED_THEBES);
@@ -1850,17 +1851,17 @@ WebRenderCommandBuilder::GenerateFallbac
   }
 
   bool needPaint = true;
   LayoutDeviceIntPoint offset = RoundedToInt(bounds.TopLeft());
   aImageRect = LayoutDeviceRect(offset, LayoutDeviceSize(RoundedToInt(bounds).Size()));
   LayerRect paintRect = LayerRect(LayerPoint(0, 0), LayerSize(paintSize));
   nsDisplayItemGeometry* geometry = fallbackData->GetGeometry();
 
-  // nsDisplayFilter is rendered via BasicLayerManager which means the invalidate
+  // nsDisplayFilters is rendered via BasicLayerManager which means the invalidate
   // region is unknown until we traverse the displaylist contained by it.
   if (geometry && !fallbackData->IsInvalid() &&
       aItem->GetType() != DisplayItemType::TYPE_FILTER &&
       aItem->GetType() != DisplayItemType::TYPE_SVG_WRAPPER &&
       differentScale) {
     nsRect invalid;
     nsRegion invalidRegion;
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -10,16 +10,17 @@
 
 #include "frontend/BytecodeEmitter.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/PodOperations.h"
+#include "mozilla/ReverseIterator.h"
 
 #include <string.h>
 
 #include "jsnum.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "ds/Nestable.h"
@@ -9625,22 +9626,22 @@ BytecodeEmitter::copySrcNotes(jssrcnote*
     unsigned mainCount = main.notes.length();
     // nsrcnotes includes SN_MAKE_TERMINATOR in addition to main.notes.
     MOZ_ASSERT(mainCount == nsrcnotes - 1);
     PodCopy(destination, main.notes.begin(), mainCount);
     SN_MAKE_TERMINATOR(&destination[mainCount]);
 }
 
 void
-CGNumberList::finish(ConstArray* array)
-{
-    MOZ_ASSERT(length() == array->length);
+CGNumberList::finish(mozilla::Span<GCPtrValue> array)
+{
+    MOZ_ASSERT(length() == array.size());
 
     for (unsigned i = 0; i < length(); i++) {
-        array->vector[i] = DoubleValue(list[i]);
+        array[i].init(DoubleValue(list[i]));
     }
 }
 
 /*
  * Find the index of the given object for code generator.
  *
  * Since the emitter refers to each parsed object only once, for the index we
  * use the number of already indexed objects. We also add the object to a list
@@ -9652,42 +9653,41 @@ CGObjectList::add(ObjectBox* objbox)
 {
     MOZ_ASSERT(!objbox->emitLink);
     objbox->emitLink = lastbox;
     lastbox = objbox;
     return length++;
 }
 
 void
-CGObjectList::finish(ObjectArray* array)
+CGObjectList::finish(mozilla::Span<GCPtrObject> array)
 {
     MOZ_ASSERT(length <= INDEX_LIMIT);
-    MOZ_ASSERT(length == array->length);
-
-    js::GCPtrObject* cursor = array->vector + array->length;
+    MOZ_ASSERT(length == array.size());
+
     ObjectBox* objbox = lastbox;
-    do {
-        --cursor;
-        MOZ_ASSERT(!*cursor);
+    for (GCPtrObject& obj : mozilla::Reversed(array)) {
+        MOZ_ASSERT(obj == nullptr);
         MOZ_ASSERT(objbox->object->isTenured());
         if (objbox->isFunctionBox()) {
             objbox->asFunctionBox()->finish();
         }
-        *cursor = objbox->object;
-    } while ((objbox = objbox->emitLink) != nullptr);
-    MOZ_ASSERT(cursor == array->vector);
+        obj.init(objbox->object);
+        objbox = objbox->emitLink;
+    }
 }
 
 void
-CGScopeList::finish(ScopeArray* array)
+CGScopeList::finish(mozilla::Span<GCPtrScope> array)
 {
     MOZ_ASSERT(length() <= INDEX_LIMIT);
-    MOZ_ASSERT(length() == array->length);
+    MOZ_ASSERT(length() == array.size());
+
     for (uint32_t i = 0; i < length(); i++) {
-        array->vector[i].init(vector[i]);
+        array[i].init(vector[i]);
     }
 }
 
 bool
 CGTryNoteList::append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end)
 {
     MOZ_ASSERT(start <= end);
     MOZ_ASSERT(size_t(uint32_t(start)) == start);
@@ -9698,22 +9698,22 @@ CGTryNoteList::append(JSTryNoteKind kind
     note.stackDepth = stackDepth;
     note.start = uint32_t(start);
     note.length = uint32_t(end - start);
 
     return list.append(note);
 }
 
 void
-CGTryNoteList::finish(TryNoteArray* array)
-{
-    MOZ_ASSERT(length() == array->length);
+CGTryNoteList::finish(mozilla::Span<JSTryNote> array)
+{
+    MOZ_ASSERT(length() == array.size());
 
     for (unsigned i = 0; i < length(); i++) {
-        array->vector[i] = list[i];
+        array[i] = list[i];
     }
 }
 
 bool
 CGScopeNoteList::append(uint32_t scopeIndex, uint32_t offset, bool inPrologue,
                         uint32_t parent)
 {
     CGScopeNote note;
@@ -9732,37 +9732,37 @@ CGScopeNoteList::recordEnd(uint32_t inde
 {
     MOZ_ASSERT(index < length());
     MOZ_ASSERT(list[index].length == 0);
     list[index].end = offset;
     list[index].endInPrologue = inPrologue;
 }
 
 void
-CGScopeNoteList::finish(ScopeNoteArray* array, uint32_t prologueLength)
-{
-    MOZ_ASSERT(length() == array->length);
+CGScopeNoteList::finish(mozilla::Span<ScopeNote> array, uint32_t prologueLength)
+{
+    MOZ_ASSERT(length() == array.size());
 
     for (unsigned i = 0; i < length(); i++) {
         if (!list[i].startInPrologue) {
             list[i].start += prologueLength;
         }
         if (!list[i].endInPrologue && list[i].end != UINT32_MAX) {
             list[i].end += prologueLength;
         }
         MOZ_ASSERT(list[i].end >= list[i].start);
         list[i].length = list[i].end - list[i].start;
-        array->vector[i] = list[i];
+        array[i] = list[i];
     }
 }
 
 void
-CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
-{
-    MOZ_ASSERT(length() == array.length());
+CGYieldAndAwaitOffsetList::finish(mozilla::Span<uint32_t> array, uint32_t prologueLength)
+{
+    MOZ_ASSERT(length() == array.size());
 
     for (unsigned i = 0; i < length(); i++) {
         array[i] = prologueLength + list[i];
     }
 }
 
 const JSSrcNoteSpec js_SrcNoteSpec[] = {
 #define DEFINE_SRC_NOTE_SPEC(sym, name, arity) { name, arity },
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* JS bytecode generation. */
 
 #ifndef frontend_BytecodeEmitter_h
 #define frontend_BytecodeEmitter_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/Span.h"
 
 #include "ds/InlineTable.h"
 #include "frontend/BCEParserHandle.h"
 #include "frontend/EitherParser.h"
 #include "frontend/JumpList.h"
 #include "frontend/NameFunctions.h"
 #include "frontend/SharedContext.h"
 #include "frontend/SourceNotes.h"
@@ -29,48 +30,48 @@ class CGNumberList {
     Vector<double> list;
 
   public:
     explicit CGNumberList(JSContext* cx) : list(cx) {}
     MOZ_MUST_USE bool append(double v) {
         return list.append(v);
     }
     size_t length() const { return list.length(); }
-    void finish(ConstArray* array);
+    void finish(mozilla::Span<GCPtrValue> array);
 };
 
 struct CGObjectList {
     uint32_t            length;     /* number of emitted so far objects */
     ObjectBox*          lastbox;   /* last emitted object */
 
     CGObjectList() : length(0), lastbox(nullptr) {}
 
     unsigned add(ObjectBox* objbox);
-    void finish(ObjectArray* array);
+    void finish(mozilla::Span<GCPtrObject> array);
 };
 
 struct MOZ_STACK_CLASS CGScopeList {
     Rooted<GCVector<Scope*>> vector;
 
     explicit CGScopeList(JSContext* cx)
       : vector(cx, GCVector<Scope*>(cx))
     { }
 
     bool append(Scope* scope) { return vector.append(scope); }
     uint32_t length() const { return vector.length(); }
-    void finish(ScopeArray* array);
+    void finish(mozilla::Span<GCPtrScope> array);
 };
 
 struct CGTryNoteList {
     Vector<JSTryNote> list;
     explicit CGTryNoteList(JSContext* cx) : list(cx) {}
 
     MOZ_MUST_USE bool append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end);
     size_t length() const { return list.length(); }
-    void finish(TryNoteArray* array);
+    void finish(mozilla::Span<JSTryNote> array);
 };
 
 struct CGScopeNote : public ScopeNote
 {
     // The end offset. Used to compute the length; may need adjusting first if
     // in the prologue.
     uint32_t end;
 
@@ -84,28 +85,28 @@ struct CGScopeNote : public ScopeNote
 struct CGScopeNoteList {
     Vector<CGScopeNote> list;
     explicit CGScopeNoteList(JSContext* cx) : list(cx) {}
 
     MOZ_MUST_USE bool append(uint32_t scopeIndex, uint32_t offset, bool inPrologue,
                              uint32_t parent);
     void recordEnd(uint32_t index, uint32_t offset, bool inPrologue);
     size_t length() const { return list.length(); }
-    void finish(ScopeNoteArray* array, uint32_t prologueLength);
+    void finish(mozilla::Span<ScopeNote> array, uint32_t prologueLength);
 };
 
 struct CGYieldAndAwaitOffsetList {
     Vector<uint32_t> list;
     uint32_t numYields;
     uint32_t numAwaits;
     explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx), numYields(0), numAwaits(0) {}
 
     MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
     size_t length() const { return list.length(); }
-    void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
+    void finish(mozilla::Span<uint32_t> 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;
 
 // Used to control whether JSOP_CALL_IGNORES_RV is emitted for function calls.
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -484,49 +484,48 @@ GetNextNonLoopEntryPc(jsbytecode* pc, js
 
 static bool
 HasLiveStackValueAtDepth(JSScript* script, jsbytecode* pc, uint32_t stackDepth)
 {
     if (!script->hasTrynotes()) {
         return false;
     }
 
-    JSTryNote* tn = script->trynotes()->vector;
-    JSTryNote* tnEnd = tn + script->trynotes()->length;
     uint32_t pcOffset = uint32_t(pc - script->main());
-    for (; tn != tnEnd; ++tn) {
-        if (pcOffset < tn->start) {
+
+    for (const JSTryNote& tn : script->trynotes()) {
+        if (pcOffset < tn.start) {
             continue;
         }
-        if (pcOffset >= tn->start + tn->length) {
+        if (pcOffset >= tn.start + tn.length) {
             continue;
         }
 
-        switch (tn->kind) {
+        switch (tn.kind) {
           case JSTRY_FOR_IN:
             // For-in loops have only the iterator on stack.
-            if (stackDepth == tn->stackDepth) {
+            if (stackDepth == tn.stackDepth) {
                 return true;
             }
             break;
 
           case JSTRY_FOR_OF:
             // For-of loops have the iterator, its next method and the
             // result.value on stack.
             // The iterator is below the result.value, the next method below
             // the iterator.
-            if (stackDepth == tn->stackDepth - 1 || stackDepth == tn->stackDepth - 2) {
+            if (stackDepth == tn.stackDepth - 1 || stackDepth == tn.stackDepth - 2) {
                 return true;
             }
             break;
 
           case JSTRY_DESTRUCTURING_ITERCLOSE:
             // Destructuring code that need to call IteratorClose have both
             // the iterator and the "done" value on the stack.
-            if (stackDepth == tn->stackDepth || stackDepth == tn->stackDepth - 1) {
+            if (stackDepth == tn.stackDepth || stackDepth == tn.stackDepth - 1) {
                 return true;
             }
             break;
 
           default:
             break;
         }
     }
--- a/js/src/jit/BytecodeAnalysis.cpp
+++ b/js/src/jit/BytecodeAnalysis.cpp
@@ -112,24 +112,22 @@ BytecodeAnalysis::init(TempAllocator& al
                     infos_[targetOffset].jumpTarget = true;
                 }
                 pc2 += JUMP_OFFSET_LEN;
             }
             break;
           }
 
           case JSOP_TRY: {
-            JSTryNote* tn = script_->trynotes()->vector;
-            JSTryNote* tnlimit = tn + script_->trynotes()->length;
-            for (; tn < tnlimit; tn++) {
-                unsigned startOffset = script_->mainOffset() + tn->start;
+            for (const JSTryNote& tn : script_->trynotes()) {
+                unsigned startOffset = script_->mainOffset() + tn.start;
                 if (startOffset == offset + 1) {
-                    unsigned catchOffset = startOffset + tn->length;
+                    unsigned catchOffset = startOffset + tn.length;
 
-                    if (tn->kind != JSTRY_FOR_IN) {
+                    if (tn.kind != JSTRY_FOR_IN) {
                         infos_[catchOffset].init(stackDepth);
                         infos_[catchOffset].jumpTarget = true;
                     }
                 }
             }
 
             // Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
             // jump over the catch/finally blocks.
--- a/js/src/jit/IonControlFlow.cpp
+++ b/js/src/jit/IonControlFlow.cpp
@@ -559,20 +559,18 @@ ControlFlowGenerator::processLabelEnd(CF
 
 ControlFlowGenerator::ControlStatus
 ControlFlowGenerator::processTry()
 {
     MOZ_ASSERT(JSOp(*pc) == JSOP_TRY);
 
     // Try-finally is not yet supported.
     if (!checkedTryFinally_) {
-        JSTryNote* tn = script->trynotes()->vector;
-        JSTryNote* tnlimit = tn + script->trynotes()->length;
-        for (; tn < tnlimit; tn++) {
-            if (tn->kind == JSTRY_FINALLY) {
+        for (const JSTryNote& tn : script->trynotes()) {
+            if (tn.kind == JSTRY_FINALLY) {
                 return ControlStatus::Abort;
             }
         }
         checkedTryFinally_ = true;
     }
 
     jssrcnote* sn = GetSrcNote(gsn, script, pc);
     MOZ_ASSERT(SN_TYPE(sn) == SRC_TRY);
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -100,17 +100,17 @@ ReadFrameBooleanSlot(JitFrameLayout* fp,
 static uint32_t
 NumArgAndLocalSlots(const InlineFrameIterator& frame)
 {
     JSScript* script = frame.script();
     return CountArgSlots(script, frame.maybeCalleeTemplate()) + script->nfixed();
 }
 
 static void
-CloseLiveIteratorIon(JSContext* cx, const InlineFrameIterator& frame, JSTryNote* tn)
+CloseLiveIteratorIon(JSContext* cx, const InlineFrameIterator& frame, const JSTryNote* tn)
 {
     MOZ_ASSERT(tn->kind == JSTRY_FOR_IN ||
                tn->kind == JSTRY_DESTRUCTURING_ITERCLOSE);
 
     bool isDestructuring = tn->kind == JSTRY_DESTRUCTURING_ITERCLOSE;
     MOZ_ASSERT_IF(!isDestructuring, tn->stackDepth > 0);
     MOZ_ASSERT_IF(isDestructuring, tn->stackDepth > 1);
 
@@ -218,17 +218,17 @@ HandleExceptionIon(JSContext* cx, const 
     RootedScript script(cx, frame.script());
     if (!script->hasTrynotes()) {
         return;
     }
 
     bool inForOfIterClose = false;
 
     for (TryNoteIterIon tni(cx, frame); !tni.done(); ++tni) {
-        JSTryNote* tn = *tni;
+        const JSTryNote* tn = *tni;
 
         switch (tn->kind) {
           case JSTRY_FOR_IN:
           case JSTRY_DESTRUCTURING_ITERCLOSE:
             // See corresponding comment in ProcessTryNotes.
             if (inForOfIterClose) {
                 break;
             }
@@ -300,27 +300,27 @@ OnLeaveBaselineFrame(JSContext* cx, cons
 static inline void
 ForcedReturn(JSContext* cx, const JSJitFrameIter& frame, jsbytecode* pc,
              ResumeFromException* rfe)
 {
     OnLeaveBaselineFrame(cx, frame, pc, rfe, true);
 }
 
 static inline void
-BaselineFrameAndStackPointersFromTryNote(JSTryNote* tn, const JSJitFrameIter& frame,
+BaselineFrameAndStackPointersFromTryNote(const JSTryNote* tn, const JSJitFrameIter& frame,
                                          uint8_t** framePointer, uint8_t** stackPointer)
 {
     JSScript* script = frame.baselineFrame()->script();
     *framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
     *stackPointer = *framePointer - BaselineFrame::Size() -
                     (script->nfixed() + tn->stackDepth) * sizeof(Value);
 }
 
 static void
-SettleOnTryNote(JSContext* cx, JSTryNote* tn, const JSJitFrameIter& frame,
+SettleOnTryNote(JSContext* cx, const JSTryNote* tn, const JSJitFrameIter& frame,
                 EnvironmentIter& ei, ResumeFromException* rfe, jsbytecode** pc)
 {
     RootedScript script(cx, frame.baselineFrame()->script());
 
     // Unwind environment chain (pop block objects).
     if (cx->isExceptionPending()) {
         UnwindEnvironment(cx, ei, UnwindEnvironmentToTryPc(script, tn));
     }
@@ -371,17 +371,17 @@ class TryNoteIterBaseline : public TryNo
 // Close all live iterators on a BaselineFrame due to exception unwinding. The
 // pc parameter is updated to where the envs have been unwound to.
 static void
 CloseLiveIteratorsBaselineForUncatchableException(JSContext* cx, const JSJitFrameIter& frame,
                                                   jsbytecode* pc)
 {
     bool inForOfIterClose = false;
     for (TryNoteIterBaseline tni(cx, frame.baselineFrame(), pc); !tni.done(); ++tni) {
-        JSTryNote* tn = *tni;
+        const JSTryNote* tn = *tni;
         switch (tn->kind) {
           case JSTRY_FOR_IN: {
             // See corresponding comment in ProcessTryNotes.
             if (inForOfIterClose) {
                 break;
             }
 
             uint8_t* framePointer;
@@ -410,17 +410,17 @@ CloseLiveIteratorsBaselineForUncatchable
 static bool
 ProcessTryNotesBaseline(JSContext* cx, const JSJitFrameIter& frame, EnvironmentIter& ei,
                         ResumeFromException* rfe, jsbytecode** pc)
 {
     RootedScript script(cx, frame.baselineFrame()->script());
     bool inForOfIterClose = false;
 
     for (TryNoteIterBaseline tni(cx, frame.baselineFrame(), *pc); !tni.done(); ++tni) {
-        JSTryNote* tn = *tni;
+        const JSTryNote* tn = *tni;
 
         MOZ_ASSERT(cx->isExceptionPending());
         switch (tn->kind) {
           case JSTRY_CATCH: {
             // If we're closing a legacy generator, we have to skip catch
             // blocks.
             if (cx->isClosingGenerator()) {
                 break;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3067,63 +3067,59 @@ TryNotes(JSContext* cx, HandleScript scr
     if (!script->hasTrynotes()) {
         return true;
     }
 
     if (!sp->put("\nException table:\nkind               stack    start      end\n")) {
         return false;
     }
 
-    JSTryNote* tn = script->trynotes()->vector;
-    JSTryNote* tnlimit = tn + script->trynotes()->length;
-    do {
-        uint32_t startOff = script->pcToOffset(script->main()) + tn->start;
+    for (const JSTryNote& tn : script->trynotes()) {
+        uint32_t startOff = script->pcToOffset(script->main()) + tn.start;
         if (!sp->jsprintf(" %-16s %6u %8u %8u\n",
-                          TryNoteName(static_cast<JSTryNoteKind>(tn->kind)),
-                          tn->stackDepth, startOff, startOff + tn->length))
+                          TryNoteName(static_cast<JSTryNoteKind>(tn.kind)),
+                          tn.stackDepth, startOff, startOff + tn.length))
         {
             return false;
         }
-    } while (++tn != tnlimit);
+    }
     return true;
 }
 
 static MOZ_MUST_USE bool
 ScopeNotes(JSContext* cx, HandleScript script, Sprinter* sp)
 {
     if (!script->hasScopeNotes()) {
         return true;
     }
 
     if (!sp->put("\nScope notes:\n   index   parent    start      end\n")) {
         return false;
     }
 
-    ScopeNoteArray* notes = script->scopeNotes();
-    for (uint32_t i = 0; i < notes->length; i++) {
-        const ScopeNote* note = &notes->vector[i];
-        if (note->index == ScopeNote::NoScopeIndex) {
+    for (const ScopeNote& note : script->scopeNotes()) {
+        if (note.index == ScopeNote::NoScopeIndex) {
             if (!sp->jsprintf("%8s ", "(none)")) {
                 return false;
             }
         } else {
-            if (!sp->jsprintf("%8u ", note->index)) {
-                return false;
-            }
-        }
-        if (note->parent == ScopeNote::NoScopeIndex) {
+            if (!sp->jsprintf("%8u ", note.index)) {
+                return false;
+            }
+        }
+        if (note.parent == ScopeNote::NoScopeIndex) {
             if (!sp->jsprintf("%8s ", "(none)")) {
                 return false;
             }
         } else {
-            if (!sp->jsprintf("%8u ", note->parent)) {
-                return false;
-            }
-        }
-        if (!sp->jsprintf("%8u %8u\n", note->start, note->start + note->length)) {
+            if (!sp->jsprintf("%8u ", note.parent)) {
+                return false;
+            }
+        }
+        if (!sp->jsprintf("%8u %8u\n", note.start, note.start + note.length)) {
             return false;
         }
     }
     return true;
 }
 
 static MOZ_MUST_USE bool
 DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun,
@@ -3184,19 +3180,17 @@ DisassembleScript(JSContext* cx, HandleS
     if (!TryNotes(cx, script, sp)) {
         return false;
     }
     if (!ScopeNotes(cx, script, sp)) {
         return false;
     }
 
     if (recursive && script->hasObjects()) {
-        ObjectArray* objects = script->objects();
-        for (unsigned i = 0; i != objects->length; ++i) {
-            JSObject* obj = objects->vector[i];
+        for (JSObject* obj : script->objects()) {
             if (obj->is<JSFunction>()) {
                 if (!sp->put("\n")) {
                     return false;
                 }
 
                 RootedFunction fun(cx, &obj->as<JSFunction>());
                 if (fun->isInterpreted()) {
                     RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
--- a/js/src/tests/non262/Promise/enqueue-promise-reactions.js
+++ b/js/src/tests/non262/Promise/enqueue-promise-reactions.js
@@ -7,17 +7,17 @@ function onResolved(val) {
 function onRejected(val) {
     result = 'rejected with ' + val;
 }
 
 // Replacing `Promise#then` shouldn't affect addPromiseReactions.
 Promise.prototype.then = 1;
 
 // Replacing Promise@@species shouldn't affect addPromiseReactions.
-Promise[Symbol.species] = function(){};
+Object.defineProperty(Promise, Symbol.species, { get: function(){} });
 
 // Replacing `Promise` shouldn't affect addPromiseReactions.
 let PromiseCtor = Promise;
 Promise = {};
 
 let result;
 let res;
 let rej;
--- a/js/src/tests/non262/Promise/get-wait-for-all-promise.js
+++ b/js/src/tests/non262/Promise/get-wait-for-all-promise.js
@@ -8,17 +8,17 @@ function onRejected(val) {
     result = 'rejected with ' + val;
 }
 
 // Replacing `Promise#then` shouldn't affect getWaitForAllPromise.
 let originalThen = Promise.prototype.then;
 Promise.prototype.then = 1;
 
 // Replacing Promise[@@species] shouldn't affect getWaitForAllPromise.
-Promise[Symbol.species] = function(){};
+Object.defineProperty(Promise, Symbol.species, { get: function(){} });
 
 // Replacing `Promise` shouldn't affect getWaitForAllPromise.
 let PromiseCtor = Promise;
 Promise = {};
 
 // Replacing Array[@@iterator] shouldn't affect getWaitForAllPromise.
 Array.prototype[Symbol.iterator] = function(){};
 
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -8,16 +8,17 @@
  * JS bytecode descriptors, disassemblers, and (expression) decompilers.
  */
 
 #include "vm/BytecodeUtil-inl.h"
 
 #define __STDC_FORMAT_MACROS
 
 #include "mozilla/Attributes.h"
+#include "mozilla/ReverseIterator.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/Vector.h"
 
 #include <algorithm>
 #include <ctype.h>
 #include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
@@ -940,29 +941,27 @@ BytecodeParser::parse()
             break;
           }
 
           case JSOP_TRY: {
             // Everything between a try and corresponding catch or finally is conditional.
             // Note that there is no problem with code which is skipped by a thrown
             // exception but is not caught by a later handler in the same function:
             // no more code will execute, and it does not matter what is defined.
-            JSTryNote* tn = script_->trynotes()->vector;
-            JSTryNote* tnlimit = tn + script_->trynotes()->length;
-            for (; tn < tnlimit; tn++) {
-                uint32_t startOffset = script_->mainOffset() + tn->start;
+            for (const JSTryNote& tn : script_->trynotes()) {
+                uint32_t startOffset = script_->mainOffset() + tn.start;
                 if (startOffset == offset + 1) {
-                    uint32_t catchOffset = startOffset + tn->length;
-                    if (tn->kind == JSTRY_CATCH) {
+                    uint32_t catchOffset = startOffset + tn.length;
+                    if (tn.kind == JSTRY_CATCH) {
                         if (!addJump(catchOffset, &nextOffset, stackDepth, offsetStack,
                                      pc, JumpKind::TryCatch))
                         {
                             return false;
                         }
-                    } else if (tn->kind == JSTRY_FINALLY) {
+                    } else if (tn.kind == JSTRY_FINALLY) {
                         if (!addJump(catchOffset, &nextOffset, stackDepth, offsetStack,
                                      pc, JumpKind::TryFinally))
                         {
                             return false;
                         }
                     }
                 }
             }
@@ -1450,25 +1449,22 @@ Disassemble1(JSContext* cx, HandleScript
     int i;
     switch (JOF_TYPE(cs->format)) {
       case JOF_BYTE:
           // Scan the trynotes to find the associated catch block
           // and make the try opcode look like a jump instruction
           // with an offset. This simplifies code coverage analysis
           // based on this disassembled output.
           if (op == JSOP_TRY) {
-              TryNoteArray* trynotes = script->trynotes();
-              uint32_t i;
               size_t mainOffset = script->mainOffset();
-              for(i = 0; i < trynotes->length; i++) {
-                  JSTryNote note = trynotes->vector[i];
-                  if (note.kind == JSTRY_CATCH && note.start + mainOffset == loc + 1) {
+              for (const JSTryNote& tn : script->trynotes()) {
+                  if (tn.kind == JSTRY_CATCH && tn.start + mainOffset == loc + 1) {
                       if (!sp->jsprintf(" %u (%+d)",
-                                        unsigned(loc + note.length + 1),
-                                        int(note.length + 1)))
+                                        unsigned(loc + tn.length + 1),
+                                        int(tn.length + 1)))
                       {
                           return 0;
                       }
                       break;
                   }
               }
           }
         break;
@@ -3115,20 +3111,18 @@ GenerateLcovInfo(JSContext* cx, JS::Real
 
             // Iterate from the last to the first object in order to have
             // the functions them visited in the opposite order when popping
             // elements from the stack of remaining scripts, such that the
             // functions are more-less listed with increasing line numbers.
             if (!script->hasObjects()) {
                 continue;
             }
-            size_t idx = script->objects()->length;
-            while (idx--) {
-                JSObject* obj = script->getObject(idx);
-
+            auto objects = script->objects();
+            for (JSObject* obj : mozilla::Reversed(objects)) {
                 // Only continue on JSFunction objects.
                 if (!obj->is<JSFunction>()) {
                     continue;
                 }
                 fun = &obj->as<JSFunction>();
 
                 // Let's skip wasm for now.
                 if (!fun->isInterpreted()) {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6233,22 +6233,20 @@ DebuggerScript_getChildScripts(JSContext
     if (!result) {
         return false;
     }
     if (script->hasObjects()) {
         // script->savedCallerFun indicates that this is a direct eval script
         // and the calling function is stored as script->objects()->vector[0].
         // It is not really a child script of this script, so skip it using
         // innerObjectsStart().
-        ObjectArray* objects = script->objects();
         RootedFunction fun(cx);
         RootedScript funScript(cx);
-        RootedObject obj(cx), s(cx);
-        for (uint32_t i = 0; i < objects->length; i++) {
-            obj = objects->vector[i];
+        RootedObject s(cx);
+        for (const GCPtrObject& obj : script->objects()) {
             if (obj->is<JSFunction>()) {
                 fun = &obj->as<JSFunction>();
                 // The inner function could be a wasm native.
                 if (fun->isNative()) {
                     continue;
                 }
                 funScript = GetOrCreateFunctionScript(cx, fun);
                 if (!funScript) {
@@ -6424,23 +6422,21 @@ class FlowGraphSummary {
                     pc += step;
                 }
             } else if (op == JSOP_TRY) {
                 // As there is no literal incoming edge into the catch block, we
                 // make a fake one by copying the JSOP_TRY location, as-if this
                 // was an incoming edge of the catch block. This is needed
                 // because we only report offsets of entry points which have
                 // valid incoming edges.
-                JSTryNote* tn = script->trynotes()->vector;
-                JSTryNote* tnlimit = tn + script->trynotes()->length;
-                for (; tn < tnlimit; tn++) {
-                    uint32_t startOffset = script->mainOffset() + tn->start;
+                for (const JSTryNote& tn : script->trynotes()) {
+                    uint32_t startOffset = script->mainOffset() + tn.start;
                     if (startOffset == r.frontOffset() + 1) {
-                        uint32_t catchOffset = startOffset + tn->length;
-                        if (tn->kind == JSTRY_CATCH || tn->kind == JSTRY_FINALLY) {
+                        uint32_t catchOffset = startOffset + tn.length;
+                        if (tn.kind == JSTRY_CATCH || tn.kind == JSTRY_FINALLY) {
                             addEdge(lineno, column, catchOffset);
                         }
                     }
                 }
             }
 
             prevLineno = lineno;
             prevColumn = column;
@@ -7450,27 +7446,24 @@ class DebuggerScriptIsInCatchScopeMatche
             return false;
         }
 
         // Try note ranges are relative to the mainOffset of the script, so adjust
         // offset accordingly.
         size_t offset = offset_ - script->mainOffset();
 
         if (script->hasTrynotes()) {
-            JSTryNote* tnBegin = script->trynotes()->vector;
-            JSTryNote* tnEnd = tnBegin + script->trynotes()->length;
-            while (tnBegin != tnEnd) {
-                if (tnBegin->start <= offset &&
-                    offset <= tnBegin->start + tnBegin->length &&
-                    tnBegin->kind == JSTRY_CATCH)
+            for (const JSTryNote& tn : script->trynotes()) {
+                if (tn.start <= offset &&
+                    offset <= tn.start + tn.length &&
+                    tn.kind == JSTRY_CATCH)
                 {
                     isInCatch_ = true;
                     return true;
                 }
-                ++tnBegin;
             }
         }
         isInCatch_ = false;
         return true;
     }
     ReturnType match(Handle<LazyScript*> lazyScript) {
         RootedScript script(cx_, DelazifyScript(cx_, lazyScript));
         if (!script) {
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -3907,21 +3907,19 @@ RemoveReferencedNames(JSContext* cx, Han
         }
 
         if (name) {
             remainingNames.remove(name);
         }
     }
 
     if (script->hasObjects()) {
-        ObjectArray* objects = script->objects();
         RootedFunction fun(cx);
         RootedScript innerScript(cx);
-        for (size_t i = 0; i < objects->length; i++) {
-            JSObject* obj = objects->vector[i];
+        for (JSObject* obj : script->objects()) {
             if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
                 fun = &obj->as<JSFunction>();
                 innerScript = JSFunction::getOrCreateScript(cx, fun);
                 if (!innerScript) {
                     return false;
                 }
 
                 if (!RemoveReferencedNames(cx, innerScript, remainingNames)) {
@@ -3979,21 +3977,19 @@ AnalyzeEntrainedVariablesInScript(JSCont
             buf.printf(" ");
             buf.putString(r.front());
         }
 
         printf("%s\n", buf.string());
     }
 
     if (innerScript->hasObjects()) {
-        ObjectArray* objects = innerScript->objects();
         RootedFunction fun(cx);
         RootedScript innerInnerScript(cx);
-        for (size_t i = 0; i < objects->length; i++) {
-            JSObject* obj = objects->vector[i];
+        for (JSObject* obj : script->objects()) {
             if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
                 fun = &obj->as<JSFunction>();
                 innerInnerScript = JSFunction::getOrCreateScript(cx, fun);
                 if (!innerInnerScript ||
                     !AnalyzeEntrainedVariablesInScript(cx, script, innerInnerScript))
                 {
                     return false;
                 }
@@ -4017,21 +4013,19 @@ AnalyzeEntrainedVariablesInScript(JSCont
 // |bar| unnecessarily entrains |b|, and |baz| unnecessarily entrains |a|.
 bool
 js::AnalyzeEntrainedVariables(JSContext* cx, HandleScript script)
 {
     if (!script->hasObjects()) {
         return true;
     }
 
-    ObjectArray* objects = script->objects();
     RootedFunction fun(cx);
     RootedScript innerScript(cx);
-    for (size_t i = 0; i < objects->length; i++) {
-        JSObject* obj = objects->vector[i];
+    for (JSObject* obj : script->objects()) {
         if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
             fun = &obj->as<JSFunction>();
             innerScript = JSFunction::getOrCreateScript(cx, fun);
             if (!innerScript) {
                 return false;
             }
 
             if (script->functionDelazifying() && script->functionDelazifying()->needsCallObject()) {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1298,17 +1298,17 @@ js::UnwindAllEnvironmentsInFrame(JSConte
 // block. We cannot unwind to *after* the JSOP_TRY, because that might be the
 // first opcode of an inner scope, with the same problem as above. e.g.,
 //
 // try { { let x; } }
 //
 // will have no pc location distinguishing the try block scope from the inner
 // let block scope.
 jsbytecode*
-js::UnwindEnvironmentToTryPc(JSScript* script, JSTryNote* tn)
+js::UnwindEnvironmentToTryPc(JSScript* script, const JSTryNote* tn)
 {
     jsbytecode* pc = script->main() + tn->start;
     if (tn->kind == JSTRY_CATCH || tn->kind == JSTRY_FINALLY) {
         pc -= JSOP_TRY_LENGTH;
         MOZ_ASSERT(*pc == JSOP_TRY);
     } else if (tn->kind == JSTRY_DESTRUCTURING_ITERCLOSE) {
         pc -= JSOP_TRY_DESTRUCTURING_ITERCLOSE_LENGTH;
         MOZ_ASSERT(*pc == JSOP_TRY_DESTRUCTURING_ITERCLOSE);
@@ -1322,17 +1322,17 @@ ForcedReturn(JSContext* cx, InterpreterR
     bool ok = Debugger::onLeaveFrame(cx, regs.fp(), regs.pc, true);
     // Point the frame to the end of the script, regardless of error. The
     // caller must jump to the correct continuation depending on 'ok'.
     regs.setToEndOfScript();
     return ok;
 }
 
 static void
-SettleOnTryNote(JSContext* cx, JSTryNote* tn, EnvironmentIter& ei, InterpreterRegs& regs)
+SettleOnTryNote(JSContext* cx, const JSTryNote* tn, EnvironmentIter& ei, InterpreterRegs& regs)
 {
     // Unwind the environment to the beginning of the JSOP_TRY.
     UnwindEnvironment(cx, ei, UnwindEnvironmentToTryPc(regs.fp()->script(), tn));
 
     // Set pc to the first bytecode after the the try note to point
     // to the beginning of catch or finally.
     regs.pc = regs.fp()->script()->main() + tn->start + tn->length;
     regs.sp = regs.spForStackDepth(tn->stackDepth);
@@ -1358,17 +1358,17 @@ class TryNoteIterInterpreter : public Tr
 
 static void
 UnwindIteratorsForUncatchableException(JSContext* cx, const InterpreterRegs& regs)
 {
     // c.f. the regular (catchable) TryNoteIterInterpreter loop in
     // ProcessTryNotes.
     bool inForOfIterClose = false;
     for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
-        JSTryNote* tn = *tni;
+        const JSTryNote* tn = *tni;
         switch (tn->kind) {
           case JSTRY_FOR_IN: {
             // See corresponding comment in ProcessTryNotes.
             if (inForOfIterClose) {
                 break;
             }
 
             Value* sp = regs.spForStackDepth(tn->stackDepth);
@@ -1398,17 +1398,17 @@ enum HandleErrorContinuation
     FinallyContinuation
 };
 
 static HandleErrorContinuation
 ProcessTryNotes(JSContext* cx, EnvironmentIter& ei, InterpreterRegs& regs)
 {
     bool inForOfIterClose = false;
     for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
-        JSTryNote* tn = *tni;
+        const JSTryNote* tn = *tni;
 
         switch (tn->kind) {
           case JSTRY_CATCH:
             /* Catch cannot intercept the closing of a generator. */
             if (cx->isClosingGenerator()) {
                 break;
             }
 
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -340,27 +340,28 @@ UnwindEnvironment(JSContext* cx, Environ
 
 // Unwind all environments.
 extern void
 UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei);
 
 // Compute the pc needed to unwind the scope to the beginning of the block
 // pointed to by the try note.
 extern jsbytecode*
-UnwindEnvironmentToTryPc(JSScript* script, JSTryNote* tn);
+UnwindEnvironmentToTryPc(JSScript* script, const JSTryNote* tn);
 
 template <class StackDepthOp>
 class MOZ_STACK_CLASS TryNoteIter
 {
     RootedScript script_;
     uint32_t pcOffset_;
-    JSTryNote* tn_;
-    JSTryNote* tnEnd_;
     StackDepthOp getStackDepth_;
 
+    const JSTryNote* tn_;
+    const JSTryNote* tnEnd_;
+
     void settle() {
         for (; tn_ != tnEnd_; ++tn_) {
             /* If pc is out of range, try the next one. */
             if (pcOffset_ - tn_->start >= tn_->length) {
                 continue;
             }
 
             /*
@@ -391,31 +392,34 @@ class MOZ_STACK_CLASS TryNoteIter
   public:
     TryNoteIter(JSContext* cx, JSScript* script, jsbytecode* pc,
                 StackDepthOp getStackDepth)
       : script_(cx, script),
         pcOffset_(pc - script->main()),
         getStackDepth_(getStackDepth)
     {
         if (script->hasTrynotes()) {
-            tn_ = script->trynotes()->vector;
-            tnEnd_ = tn_ + script->trynotes()->length;
+            // NOTE: The Span is a temporary so we can't use begin()/end()
+            // here or the iterator will outlive the span.
+            auto trynotes = script->trynotes();
+            tn_ = trynotes.data();
+            tnEnd_ = tn_ + trynotes.size();
         } else {
             tn_ = tnEnd_ = nullptr;
         }
         settle();
     }
 
     void operator++() {
         ++tn_;
         settle();
     }
 
     bool done() const { return tn_ == tnEnd_; }
-    JSTryNote* operator*() const { return tn_; }
+    const JSTryNote* operator*() const { return tn_; }
 };
 
 bool
 HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame, bool ok);
 
 /************************************************************************/
 
 bool
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -299,21 +299,20 @@ XDRRelazificationInfo(XDRState<mode>* xd
     // have any.
 
     return Ok();
 }
 
 static inline uint32_t
 FindScopeIndex(JSScript* script, Scope& scope)
 {
-    ScopeArray* scopes = script->scopes();
-    GCPtrScope* vector = scopes->vector;
-    unsigned length = scopes->length;
+    auto scopes = script->scopes();
+    unsigned length = scopes.size();
     for (uint32_t i = 0; i < length; ++i) {
-        if (vector[i] == &scope) {
+        if (scopes[i] == &scope) {
             return i;
         }
     }
 
     MOZ_CRASH("Scope not found");
 }
 
 enum XDRClassKind {
@@ -353,17 +352,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         HasNonSyntacticScope,
         HasInnerFunctions,
         NeedsHomeObject,
         IsDerivedClassConstructor,
         IsDefaultClassConstructor,
     };
 
     uint32_t length, lineno, column, nfixed, nslots;
-    uint32_t natoms, nsrcnotes, i;
+    uint32_t natoms, nsrcnotes;
     uint32_t nconsts, nobjects, nscopes, nregexps, ntrynotes, nscopenotes, nyieldoffsets;
     uint32_t prologueLength;
     uint32_t funLength = 0;
     uint32_t nTypeSets = 0;
     uint32_t scriptBits = 0;
     uint32_t bodyScopeIndex = 0;
 
     JSContext* cx = xdr->cx();
@@ -403,30 +402,30 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         nslots = script->nslots();
 
         bodyScopeIndex = script->bodyScopeIndex();
         natoms = script->natoms();
 
         nsrcnotes = script->numNotes();
 
         if (script->hasConsts()) {
-            nconsts = script->consts()->length;
+            nconsts = script->consts().size();
         }
         if (script->hasObjects()) {
-            nobjects = script->objects()->length;
+            nobjects = script->objects().size();
         }
-        nscopes = script->scopes()->length;
+        nscopes = script->scopes().size();
         if (script->hasTrynotes()) {
-            ntrynotes = script->trynotes()->length;
+            ntrynotes = script->trynotes().size();
         }
         if (script->hasScopeNotes()) {
-            nscopenotes = script->scopeNotes()->length;
+            nscopenotes = script->scopeNotes().size();
         }
         if (script->hasYieldAndAwaitOffsets()) {
-            nyieldoffsets = script->yieldAndAwaitOffsets().length();
+            nyieldoffsets = script->yieldAndAwaitOffsets().size();
         }
 
         nTypeSets = script->nTypeSets();
         funLength = script->funLength();
 
         if (script->noScriptRval()) {
             scriptBits |= (1 << NoScriptRval);
         }
@@ -699,17 +698,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             script->freeScriptData();
         }
     });
 
     jsbytecode* code = script->code();
     MOZ_TRY(xdr->codeBytes(code, length));
     MOZ_TRY(xdr->codeBytes(code + length, nsrcnotes));
 
-    for (i = 0; i != natoms; ++i) {
+    for (uint32_t i = 0; i != natoms; ++i) {
         if (mode == XDR_DECODE) {
             RootedAtom tmp(cx);
             MOZ_TRY(XDRAtom(xdr, &tmp));
             script->atoms()[i].init(tmp);
         } else {
             RootedAtom tmp(cx, script->atoms()[i]);
             MOZ_TRY(XDRAtom(xdr, &tmp));
         }
@@ -718,37 +717,36 @@ js::XDRScript(XDRState<mode>* xdr, Handl
     scriptDataGuard.release();
     if (mode == XDR_DECODE) {
         if (!script->shareScriptData(cx)) {
             return xdr->fail(JS::TranscodeResult_Throw);
         }
     }
 
     if (nconsts) {
-        GCPtrValue* vector = script->consts()->vector;
         RootedValue val(cx);
-        for (i = 0; i != nconsts; ++i) {
+        for (GCPtrValue& elem : script->consts()) {
             if (mode == XDR_ENCODE) {
-                val = vector[i];
+                val = elem.get();
             }
             MOZ_TRY(XDRScriptConst(xdr, &val));
             if (mode == XDR_DECODE) {
-                vector[i].init(val);
+                elem.init(val);
             }
         }
     }
 
     {
         MOZ_ASSERT(nscopes != 0);
-        GCPtrScope* vector = script->scopes()->vector;
+        GCPtrScope* vector = script->scopes().data();
         RootedScope scope(cx);
         RootedScope enclosing(cx);
         ScopeKind scopeKind;
         uint32_t enclosingScopeIndex = 0;
-        for (i = 0; i != nscopes; ++i) {
+        for (uint32_t i = 0; i != nscopes; ++i) {
             if (mode == XDR_ENCODE) {
                 scope = vector[i];
                 scopeKind = scope->kind();
             } else {
                 scope = nullptr;
             }
 
             MOZ_TRY(xdr->codeEnum32(&scopeKind));
@@ -829,128 +827,133 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         MOZ_TRY(xdr->codeMarker(0x48922BAB));
     }
 
     /*
      * Here looping from 0-to-length to xdr objects is essential to ensure that
      * all references to enclosing blocks (via FindScopeIndex below) happen
      * after the enclosing block has been XDR'd.
      */
-    for (i = 0; i != nobjects; ++i) {
-        GCPtrObject* objp = &script->objects()->vector[i];
-        XDRClassKind classk;
-
-        if (mode == XDR_ENCODE) {
-            JSObject* obj = *objp;
-            if (obj->is<RegExpObject>()) {
-                classk = CK_RegexpObject;
-            } else if (obj->is<JSFunction>()) {
-                classk = CK_JSFunction;
-            } else if (obj->is<PlainObject>() || obj->is<ArrayObject>()) {
-                classk = CK_JSObject;
-            } else {
-                MOZ_CRASH("Cannot encode this class of object.");
-            }
-        }
-
-        MOZ_TRY(xdr->codeEnum32(&classk));
-
-        switch (classk) {
-          case CK_RegexpObject: {
-            Rooted<RegExpObject*> regexp(cx);
-            if (mode == XDR_ENCODE) {
-                regexp = &(*objp)->as<RegExpObject>();
-            }
-            MOZ_TRY(XDRScriptRegExpObject(xdr, &regexp));
-            if (mode == XDR_DECODE) {
-                *objp = regexp;
-            }
-            break;
-          }
-
-          case CK_JSFunction: {
-            /* Code the nested function's enclosing scope. */
-            uint32_t funEnclosingScopeIndex = 0;
-            RootedScope funEnclosingScope(cx);
+    if (nobjects) {
+        for (GCPtrObject& elem : script->objects()) {
+            XDRClassKind classk;
+
             if (mode == XDR_ENCODE) {
-                RootedFunction function(cx, &(*objp)->as<JSFunction>());
-
-                if (function->isInterpretedLazy()) {
-                    funEnclosingScope = function->lazyScript()->enclosingScope();
-                } else if (function->isInterpreted()) {
-                    funEnclosingScope = function->nonLazyScript()->enclosingScope();
+                JSObject* obj = elem.get();
+                if (obj->is<RegExpObject>()) {
+                    classk = CK_RegexpObject;
+                } else if (obj->is<JSFunction>()) {
+                    classk = CK_JSFunction;
+                } else if (obj->is<PlainObject>() || obj->is<ArrayObject>()) {
+                    classk = CK_JSObject;
                 } else {
-                    MOZ_ASSERT(function->isAsmJSNative());
-                    return xdr->fail(JS::TranscodeResult_Failure_AsmJSNotSupported);
+                    MOZ_CRASH("Cannot encode this class of object.");
                 }
-
-                funEnclosingScopeIndex = FindScopeIndex(script, *funEnclosingScope);
-            }
-
-            MOZ_TRY(xdr->codeUint32(&funEnclosingScopeIndex));
-
-            if (mode == XDR_DECODE) {
-                MOZ_ASSERT(funEnclosingScopeIndex < script->scopes()->length);
-                funEnclosingScope = script->scopes()->vector[funEnclosingScopeIndex];
             }
 
-            // Code nested function and script.
-            RootedFunction tmp(cx);
-            if (mode == XDR_ENCODE) {
-                tmp = &(*objp)->as<JSFunction>();
+            MOZ_TRY(xdr->codeEnum32(&classk));
+
+            switch (classk) {
+              case CK_RegexpObject: {
+                Rooted<RegExpObject*> regexp(cx);
+                if (mode == XDR_ENCODE) {
+                    regexp = &elem->as<RegExpObject>();
+                }
+                MOZ_TRY(XDRScriptRegExpObject(xdr, &regexp));
+                if (mode == XDR_DECODE) {
+                    elem.init(regexp);
+                }
+                break;
+              }
+
+              case CK_JSFunction: {
+                /* Code the nested function's enclosing scope. */
+                uint32_t funEnclosingScopeIndex = 0;
+                RootedScope funEnclosingScope(cx);
+                if (mode == XDR_ENCODE) {
+                    RootedFunction function(cx, &elem->as<JSFunction>());
+
+                    if (function->isInterpretedLazy()) {
+                        funEnclosingScope = function->lazyScript()->enclosingScope();
+                    } else if (function->isInterpreted()) {
+                        funEnclosingScope = function->nonLazyScript()->enclosingScope();
+                    } else {
+                        MOZ_ASSERT(function->isAsmJSNative());
+                        return xdr->fail(JS::TranscodeResult_Failure_AsmJSNotSupported);
+                    }
+
+                    funEnclosingScopeIndex = FindScopeIndex(script, *funEnclosingScope);
+                }
+
+                MOZ_TRY(xdr->codeUint32(&funEnclosingScopeIndex));
+
+                if (mode == XDR_DECODE) {
+                    funEnclosingScope = script->getScope(funEnclosingScopeIndex);
+                }
+
+                // Code nested function and script.
+                RootedFunction tmp(cx);
+                if (mode == XDR_ENCODE) {
+                    tmp = &elem->as<JSFunction>();
+                }
+                MOZ_TRY(XDRInterpretedFunction(xdr, funEnclosingScope, sourceObject, &tmp));
+                if (mode == XDR_DECODE) {
+                    elem.init(tmp);
+                }
+                break;
+              }
+
+              case CK_JSObject: {
+                /* Code object literal. */
+                RootedObject tmp(cx);
+                if (mode == XDR_ENCODE) {
+                    tmp = elem.get();
+                }
+                MOZ_TRY(XDRObjectLiteral(xdr, &tmp));
+                if (mode == XDR_DECODE) {
+                    elem.init(tmp);
+                }
+                break;
+              }
+
+              default: {
+                // Fail in debug, but only soft-fail in release
+                MOZ_ASSERT(false, "Bad XDR class kind");
+                return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
+              }
             }
-            MOZ_TRY(XDRInterpretedFunction(xdr, funEnclosingScope, sourceObject, &tmp));
-            *objp = tmp;
-            break;
-          }
-
-          case CK_JSObject: {
-            /* Code object literal. */
-            RootedObject tmp(cx, *objp);
-            MOZ_TRY(XDRObjectLiteral(xdr, &tmp));
-            *objp = tmp;
-            break;
-          }
-
-          default: {
-            // Fail in debug, but only soft-fail in release
-            MOZ_ASSERT(false, "Bad XDR class kind");
-            return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
-          }
         }
     }
 
     // Verify marker to detect data corruption after decoding object data. A
     // mismatch here indicates we will almost certainly crash in release.
     MOZ_TRY(xdr->codeMarker(0xF83B989A));
 
-    if (ntrynotes != 0) {
-        JSTryNote* tnfirst = script->trynotes()->vector;
-        MOZ_ASSERT(script->trynotes()->length == ntrynotes);
-        JSTryNote* tn = tnfirst + ntrynotes;
-        do {
-            --tn;
-            MOZ_TRY(xdr->codeUint8(&tn->kind));
-            MOZ_TRY(xdr->codeUint32(&tn->stackDepth));
-            MOZ_TRY(xdr->codeUint32(&tn->start));
-            MOZ_TRY(xdr->codeUint32(&tn->length));
-        } while (tn != tnfirst);
-    }
-
-    for (i = 0; i < nscopenotes; ++i) {
-        ScopeNote* note = &script->scopeNotes()->vector[i];
-        MOZ_TRY(xdr->codeUint32(&note->index));
-        MOZ_TRY(xdr->codeUint32(&note->start));
-        MOZ_TRY(xdr->codeUint32(&note->length));
-        MOZ_TRY(xdr->codeUint32(&note->parent));
-    }
-
-    for (i = 0; i < nyieldoffsets; ++i) {
-        uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
-        MOZ_TRY(xdr->codeUint32(offset));
+    if (ntrynotes) {
+        for (JSTryNote& elem : script->trynotes()) {
+            MOZ_TRY(xdr->codeUint8(&elem.kind));
+            MOZ_TRY(xdr->codeUint32(&elem.stackDepth));
+            MOZ_TRY(xdr->codeUint32(&elem.start));
+            MOZ_TRY(xdr->codeUint32(&elem.length));
+        }
+    }
+
+    if (nscopenotes) {
+        for (ScopeNote& elem : script->scopeNotes()) {
+            MOZ_TRY(xdr->codeUint32(&elem.index));
+            MOZ_TRY(xdr->codeUint32(&elem.start));
+            MOZ_TRY(xdr->codeUint32(&elem.length));
+            MOZ_TRY(xdr->codeUint32(&elem.parent));
+        }
+    }
+
+    if (nyieldoffsets) {
+        for (uint32_t& elem : script->yieldAndAwaitOffsets()) {
+            MOZ_TRY(xdr->codeUint32(&elem));
+        }
     }
 
     if (scriptBits & (1 << HasLazyScript)) {
         Rooted<LazyScript*> lazy(cx);
         if (mode == XDR_ENCODE) {
             lazy = script->maybeLazyScript();
         }
 
@@ -2962,54 +2965,54 @@ JSScript::partiallyInit(JSContext* cx, H
     YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
     if (nyieldoffsets != 0) {
         yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
         cursor += sizeof(YieldAndAwaitOffsetArray);
     }
 
     if (nconsts != 0) {
         MOZ_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(JS::Value) == 0);
-        script->consts()->length = nconsts;
-        script->consts()->vector = (GCPtrValue*)cursor;
-        cursor += nconsts * sizeof(script->consts()->vector[0]);
-    }
-
-    script->scopes()->length = nscopes;
-    script->scopes()->vector = (GCPtrScope*)cursor;
-    cursor += nscopes * sizeof(script->scopes()->vector[0]);
+        script->constsRaw()->length = nconsts;
+        script->constsRaw()->vector = (GCPtrValue*)cursor;
+        cursor += nconsts * sizeof(script->constsRaw()->vector[0]);
+    }
+
+    script->scopesRaw()->length = nscopes;
+    script->scopesRaw()->vector = (GCPtrScope*)cursor;
+    cursor += nscopes * sizeof(script->scopesRaw()->vector[0]);
 
     if (nobjects != 0) {
-        script->objects()->length = nobjects;
-        script->objects()->vector = (GCPtrObject*)cursor;
-        cursor += nobjects * sizeof(script->objects()->vector[0]);
+        script->objectsRaw()->length = nobjects;
+        script->objectsRaw()->vector = (GCPtrObject*)cursor;
+        cursor += nobjects * sizeof(script->objectsRaw()->vector[0]);
     }
 
     if (ntrynotes != 0) {
-        script->trynotes()->length = ntrynotes;
-        script->trynotes()->vector = reinterpret_cast<JSTryNote*>(cursor);
-        size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
+        script->trynotesRaw()->length = ntrynotes;
+        script->trynotesRaw()->vector = reinterpret_cast<JSTryNote*>(cursor);
+        size_t vectorSize = ntrynotes * sizeof(script->trynotesRaw()->vector[0]);
 #ifdef DEBUG
         memset(cursor, 0, vectorSize);
 #endif
         cursor += vectorSize;
     }
 
     if (nscopenotes != 0) {
-        script->scopeNotes()->length = nscopenotes;
-        script->scopeNotes()->vector = reinterpret_cast<ScopeNote*>(cursor);
-        size_t vectorSize = nscopenotes * sizeof(script->scopeNotes()->vector[0]);
+        script->scopeNotesRaw()->length = nscopenotes;
+        script->scopeNotesRaw()->vector = reinterpret_cast<ScopeNote*>(cursor);
+        size_t vectorSize = nscopenotes * sizeof(script->scopeNotesRaw()->vector[0]);
 #ifdef DEBUG
         memset(cursor, 0, vectorSize);
 #endif
         cursor += vectorSize;
     }
 
     if (nyieldoffsets != 0) {
         yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
-        size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsets()[0]);
+        size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsetsRaw()[0]);
 #ifdef DEBUG
         memset(cursor, 0, vectorSize);
 #endif
         cursor += vectorSize;
     }
 
     MOZ_ASSERT(cursor == script->data + size);
     return true;
@@ -3034,17 +3037,17 @@ JSScript::initFunctionPrototype(JSContex
     script->nTypeSets_ = 0;
 
     RootedScope enclosing(cx, &cx->global()->emptyGlobalScope());
     Scope* functionProtoScope = FunctionScope::create(cx, nullptr, false, false, functionProto,
                                                       enclosing);
     if (!functionProtoScope) {
         return false;
     }
-    script->scopes()->vector[0].init(functionProtoScope);
+    script->scopesRaw()->vector[0].init(functionProtoScope);
 
     uint32_t codeLength = 1;
     uint32_t srcNotesLength = 1;
     uint32_t numAtoms = 0;
     if (!script->createScriptData(cx, codeLength, srcNotesLength, numAtoms)) {
         return false;
     }
 
@@ -3267,27 +3270,25 @@ JSScript::assertValidJumpTargets() const
                 MOZ_ASSERT_IF(off, mainEntry <= pc + off && pc + off < end);
                 MOZ_ASSERT_IF(off, BytecodeIsJumpTarget(JSOp(*(pc + off))));
             }
         }
     }
 
     // Check catch/finally blocks as jump targets.
     if (hasTrynotes()) {
-        JSTryNote* tn = trynotes()->vector;
-        JSTryNote* tnlimit = tn + trynotes()->length;
-        for (; tn < tnlimit; tn++) {
-            jsbytecode* tryStart = mainEntry + tn->start;
+        for (const JSTryNote& tn : trynotes()) {
+            jsbytecode* tryStart = mainEntry + tn.start;
             jsbytecode* tryPc = tryStart - 1;
-            if (tn->kind != JSTRY_CATCH && tn->kind != JSTRY_FINALLY) {
+            if (tn.kind != JSTRY_CATCH && tn.kind != JSTRY_FINALLY) {
                 continue;
             }
 
             MOZ_ASSERT(JSOp(*tryPc) == JSOP_TRY);
-            jsbytecode* tryTarget = tryStart + tn->length;
+            jsbytecode* tryTarget = tryStart + tn.length;
             MOZ_ASSERT(mainEntry <= tryTarget && tryTarget < end);
             MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*tryTarget)));
         }
     }
 }
 #endif
 
 size_t
@@ -3660,22 +3661,22 @@ js::detail::CopyScript(JSContext* cx, Ha
         return false;
     }
 
     /* NB: Keep this in sync with XDRScript. */
 
     /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
     MOZ_ASSERT(!src->sourceObject()->isMarkedGray());
 
-    uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
-    uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
-    uint32_t nscopes   = src->scopes()->length;
-    uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
-    uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
-    uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().length() : 0;
+    uint32_t nconsts = src->hasConsts() ? src->consts().size() : 0;
+    uint32_t nobjects = src->hasObjects() ? src->objects().size() : 0;
+    uint32_t nscopes = src->scopes().size();
+    uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes().size() : 0;
+    uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes().size() : 0;
+    uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().size() : 0;
 
     /* Script data */
 
     size_t size = src->dataSize();
     UniquePtr<uint8_t, JS::FreePolicy> data(AllocScriptData(cx, size));
     if (size && !data) {
         return false;
     }
@@ -3684,37 +3685,35 @@ js::detail::CopyScript(JSContext* cx, Ha
 
     // The passed in scopes vector contains body scopes that needed to be
     // cloned especially, depending on whether the script is a function or
     // global scope. Starting at scopes.length() means we only deal with
     // intra-body scopes.
     {
         MOZ_ASSERT(nscopes != 0);
         MOZ_ASSERT(src->bodyScopeIndex() + 1 == scopes.length());
-        GCPtrScope* vector = src->scopes()->vector;
         RootedScope original(cx);
         RootedScope clone(cx);
-        for (uint32_t i = scopes.length(); i < nscopes; i++) {
-            original = vector[i];
+        for (const GCPtrScope& elem : src->scopes().From(scopes.length())) {
+            original = elem.get();
             clone = Scope::clone(cx, original, scopes[FindScopeIndex(src, *original->enclosing())]);
             if (!clone || !scopes.append(clone)) {
                 return false;
             }
         }
     }
 
     /* Objects */
 
     AutoObjectVector objects(cx);
     if (nobjects != 0) {
-        GCPtrObject* vector = src->objects()->vector;
         RootedObject obj(cx);
         RootedObject clone(cx);
-        for (unsigned i = 0; i < nobjects; i++) {
-            obj = vector[i];
+        for (const GCPtrObject& elem : src->objects()) {
+            obj = elem.get();
             clone = nullptr;
             if (obj->is<RegExpObject>()) {
                 clone = CloneScriptRegExpObject(cx, obj->as<RegExpObject>());
             } else if (obj->is<JSFunction>()) {
                 RootedFunction innerFun(cx, &obj->as<JSFunction>());
                 if (innerFun->isNative()) {
                     if (cx->compartment() != innerFun->compartment()) {
                         MOZ_ASSERT(innerFun->isAsmJSNative());
@@ -3791,45 +3790,45 @@ js::detail::CopyScript(JSContext* cx, Ha
     dst->bitFields_.isDerivedClassConstructor_ = src->isDerivedClassConstructor();
     dst->bitFields_.needsHomeObject_ = src->needsHomeObject();
     dst->bitFields_.isDefaultClassConstructor_ = src->isDefaultClassConstructor();
     dst->bitFields_.isAsync_ = src->bitFields_.isAsync_;
     dst->bitFields_.hasRest_ = src->bitFields_.hasRest_;
     dst->bitFields_.hideScriptFromDebugger_ = src->bitFields_.hideScriptFromDebugger_;
 
     if (nconsts != 0) {
-        GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
-        dst->consts()->vector = vector;
+        GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->constsRaw()->vector);
+        dst->constsRaw()->vector = vector;
         for (unsigned i = 0; i < nconsts; ++i) {
             MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom());
         }
     }
     if (nobjects != 0) {
-        GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objects()->vector);
-        dst->objects()->vector = vector;
+        GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objectsRaw()->vector);
+        dst->objectsRaw()->vector = vector;
         for (unsigned i = 0; i < nobjects; ++i) {
             vector[i].init(&objects[i]->as<NativeObject>());
         }
     }
     {
-        GCPtrScope* vector = Rebase<GCPtrScope>(dst, src, src->scopes()->vector);
-        dst->scopes()->vector = vector;
+        GCPtrScope* vector = Rebase<GCPtrScope>(dst, src, src->scopesRaw()->vector);
+        dst->scopesRaw()->vector = vector;
         for (uint32_t i = 0; i < nscopes; ++i) {
             vector[i].init(scopes[i]);
         }
     }
     if (ntrynotes != 0) {
-        dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
+        dst->trynotesRaw()->vector = Rebase<JSTryNote>(dst, src, src->trynotesRaw()->vector);
     }
     if (nscopenotes != 0) {
-        dst->scopeNotes()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotes()->vector);
+        dst->scopeNotesRaw()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotesRaw()->vector);
     }
     if (nyieldoffsets != 0) {
-        dst->yieldAndAwaitOffsets().vector_ =
-            Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsets().vector_);
+        dst->yieldAndAwaitOffsetsRaw().vector_ =
+            Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsetsRaw().vector_);
     }
 
     return true;
 }
 
 static JSScript*
 CreateEmptyScriptForClone(JSContext* cx, HandleScript src)
 {
@@ -4168,28 +4167,29 @@ JSScript::traceChildren(JSTracer* trc)
     MOZ_ASSERT_IF(trc->isMarkingTracer() &&
                   GCMarker::fromTracer(trc)->shouldCheckCompartments(),
                   zone()->isCollecting());
 
     if (scriptData()) {
         scriptData()->traceChildren(trc);
     }
 
-    if (ScopeArray* scopearray = scopes()) {
-        TraceRange(trc, scopearray->length, scopearray->vector, "scopes");
+    if (data) {
+        auto array = scopes();
+        TraceRange(trc, array.size(), array.data(), "scopes");
     }
 
     if (hasConsts()) {
-        ConstArray* constarray = consts();
-        TraceRange(trc, constarray->length, constarray->vector, "consts");
+        auto array = consts();
+        TraceRange(trc, array.size(), array.data(), "consts");
     }
 
     if (hasObjects()) {
-        ObjectArray* objarray = objects();
-        TraceRange(trc, objarray->length, objarray->vector, "objects");
+        auto array = objects();
+        TraceRange(trc, array.size(), array.data(), "objects");
     }
 
     MOZ_ASSERT_IF(sourceObject(), MaybeForwarded(sourceObject())->compartment() == compartment());
     TraceNullableEdge(trc, &sourceObject_, "sourceObject");
 
     if (maybeLazyScript()) {
         TraceManuallyBarrieredEdge(trc, &lazyScript, "lazyScript");
     }
@@ -4247,35 +4247,35 @@ JSScript::lookupScope(jsbytecode* pc)
     MOZ_ASSERT(containsPC(pc));
 
     if (!hasScopeNotes()) {
         return nullptr;
     }
 
     size_t offset = pc - code();
 
-    ScopeNoteArray* notes = scopeNotes();
+    auto notes = scopeNotes();
     Scope* scope = nullptr;
 
     // Find the innermost block chain using a binary search.
     size_t bottom = 0;
-    size_t top = notes->length;
+    size_t top = notes.size();
 
     while (bottom < top) {
         size_t mid = bottom + (top - bottom) / 2;
-        const ScopeNote* note = &notes->vector[mid];
+        const ScopeNote* note = &notes[mid];
         if (note->start <= offset) {
             // Block scopes are ordered in the list by their starting offset, and since
             // blocks form a tree ones earlier in the list may cover the pc even if
             // later blocks end before the pc. This only happens when the earlier block
             // is a parent of the later block, so we need to check parents of |mid| in
             // the searched range for coverage.
             size_t check = mid;
             while (check >= bottom) {
-                const ScopeNote* checkNote = &notes->vector[check];
+                const ScopeNote* checkNote = &notes[check];
                 MOZ_ASSERT(checkNote->start <= offset);
                 if (offset < checkNote->start + checkNote->length) {
                     // We found a matching block chain but there may be inner ones
                     // at a higher block chain index than mid. Continue the binary search.
                     if (checkNote->index == ScopeNote::NoScopeIndex) {
                         scope = nullptr;
                     } else {
                         scope = getScope(checkNote->index);
@@ -4719,20 +4719,18 @@ JSScript::updateJitCodeRaw(JSRuntime* rt
 }
 
 bool
 JSScript::hasLoops()
 {
     if (!hasTrynotes()) {
         return false;
     }
-    JSTryNote* tn = trynotes()->vector;
-    JSTryNote* tnlimit = tn + trynotes()->length;
-    for (; tn < tnlimit; tn++) {
-        switch (tn->kind) {
+    for (const JSTryNote& tn : trynotes()) {
+        switch (tn.kind) {
           case JSTRY_FOR_IN:
           case JSTRY_FOR_OF:
           case JSTRY_LOOP:
             return true;
           case JSTRY_CATCH:
           case JSTRY_FINALLY:
           case JSTRY_FOR_OF_ITERCLOSE:
           case JSTRY_DESTRUCTURING_ITERCLOSE:
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -8,16 +8,17 @@
 
 #ifndef vm_JSScript_h
 #define vm_JSScript_h
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Span.h"
 #include "mozilla/Variant.h"
 
 #include "jstypes.h"
 
 #include "frontend/NameAnalysisTypes.h"
 #include "gc/Barrier.h"
 #include "gc/Rooting.h"
 #include "jit/IonCode.h"
@@ -1820,28 +1821,26 @@ class JSScript : public js::gc::TenuredC
 
     bool functionHasExtraBodyVarScope() const {
         MOZ_ASSERT_IF(bitFields_.functionHasExtraBodyVarScope_, functionHasParameterExprs());
         return bitFields_.functionHasExtraBodyVarScope_;
     }
 
     js::VarScope* functionExtraBodyVarScope() const {
         MOZ_ASSERT(functionHasExtraBodyVarScope());
-        for (uint32_t i = 0; i < scopes()->length; i++) {
-            js::Scope* scope = getScope(i);
+        for (js::Scope* scope : scopes()) {
             if (scope->kind() == js::ScopeKind::FunctionBodyVar) {
                 return &scope->as<js::VarScope>();
             }
         }
         MOZ_CRASH("Function extra body var scope not found");
     }
 
     bool needsBodyEnvironment() const {
-        for (uint32_t i = 0; i < scopes()->length; i++) {
-            js::Scope* scope = getScope(i);
+        for (js::Scope* scope : scopes()) {
             if (ScopeKindIsInBody(scope->kind()) && scope->hasEnvironment()) {
                 return true;
             }
         }
         return false;
     }
 
     inline js::LexicalScope* maybeNamedLambdaScope() const;
@@ -1926,46 +1925,80 @@ class JSScript : public js::gc::TenuredC
     size_t yieldAndAwaitOffsetsOffset() const {
         return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray);
     }
 
 #undef OFF
 
     size_t dataSize() const { return dataSize_; }
 
-    js::ConstArray* consts() {
+  private:
+
+    js::ConstArray* constsRaw() const {
         MOZ_ASSERT(hasConsts());
         return reinterpret_cast<js::ConstArray*>(data + constsOffset());
     }
 
-    js::ObjectArray* objects() {
+    js::ObjectArray* objectsRaw() const {
         MOZ_ASSERT(hasObjects());
         return reinterpret_cast<js::ObjectArray*>(data + objectsOffset());
     }
 
-    js::ScopeArray* scopes() const {
+    js::ScopeArray* scopesRaw() const {
         return reinterpret_cast<js::ScopeArray*>(data + scopesOffset());
     }
 
-    js::TryNoteArray* trynotes() const {
+    js::TryNoteArray* trynotesRaw() const {
         MOZ_ASSERT(hasTrynotes());
         return reinterpret_cast<js::TryNoteArray*>(data + trynotesOffset());
     }
 
-    js::ScopeNoteArray* scopeNotes() {
+    js::ScopeNoteArray* scopeNotesRaw() const {
         MOZ_ASSERT(hasScopeNotes());
         return reinterpret_cast<js::ScopeNoteArray*>(data + scopeNotesOffset());
     }
 
-    js::YieldAndAwaitOffsetArray& yieldAndAwaitOffsets() {
+    js::YieldAndAwaitOffsetArray& yieldAndAwaitOffsetsRaw() const {
         MOZ_ASSERT(hasYieldAndAwaitOffsets());
         return *reinterpret_cast<js::YieldAndAwaitOffsetArray*>(data +
                                                                 yieldAndAwaitOffsetsOffset());
     }
 
+  public:
+
+    mozilla::Span<js::GCPtrValue> consts() const {
+        js::ConstArray* array = constsRaw();
+        return mozilla::MakeSpan(array->vector, array->length);
+    }
+
+    mozilla::Span<js::GCPtrObject> objects() const {
+        js::ObjectArray* array = objectsRaw();
+        return mozilla::MakeSpan(array->vector, array->length);
+    }
+
+    mozilla::Span<js::GCPtrScope> scopes() const {
+        js::ScopeArray* array = scopesRaw();
+        return mozilla::MakeSpan(array->vector, array->length);
+    }
+
+    mozilla::Span<JSTryNote> trynotes() const {
+        js::TryNoteArray* array = trynotesRaw();
+        return mozilla::MakeSpan(array->vector, array->length);
+    }
+
+    mozilla::Span<js::ScopeNote> scopeNotes() const {
+        js::ScopeNoteArray* array = scopeNotesRaw();
+        return mozilla::MakeSpan(array->vector, array->length);
+    }
+
+    mozilla::Span<uint32_t> yieldAndAwaitOffsets() const {
+        js::YieldAndAwaitOffsetArray& array = yieldAndAwaitOffsetsRaw();
+        return mozilla::MakeSpan(&array[0], array.length());
+    }
+
     bool hasLoops();
 
     uint32_t numNotes() const {
         MOZ_ASSERT(scriptData_);
         return scriptData_->numNotes();
     }
     jssrcnote* notes() const {
         MOZ_ASSERT(scriptData_);
@@ -1996,31 +2029,27 @@ class JSScript : public js::gc::TenuredC
         return getAtom(index)->asPropertyName();
     }
 
     js::PropertyName* getName(jsbytecode* pc) const {
         return getAtom(pc)->asPropertyName();
     }
 
     JSObject* getObject(size_t index) {
-        js::ObjectArray* arr = objects();
-        MOZ_ASSERT(index < arr->length);
-        MOZ_ASSERT(arr->vector[index]->isTenured());
-        return arr->vector[index];
+        MOZ_ASSERT(objects()[index]->isTenured());
+        return objects()[index];
     }
 
     JSObject* getObject(jsbytecode* pc) {
         MOZ_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
         return getObject(GET_UINT32_INDEX(pc));
     }
 
     js::Scope* getScope(size_t index) const {
-        js::ScopeArray* array = scopes();
-        MOZ_ASSERT(index < array->length);
-        return array->vector[index];
+        return scopes()[index];
     }
 
     js::Scope* getScope(jsbytecode* pc) const {
         // This method is used to get a scope directly using a JSOp with an
         // index. To search through ScopeNotes to look for a Scope using pc,
         // use lookupScope.
         MOZ_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
         MOZ_ASSERT(js::JOF_OPTYPE(JSOp(*pc)) == JOF_SCOPE,
@@ -2035,19 +2064,17 @@ class JSScript : public js::gc::TenuredC
         }
         return nullptr;
     }
 
     inline js::RegExpObject* getRegExp(size_t index);
     inline js::RegExpObject* getRegExp(jsbytecode* pc);
 
     const js::Value& getConst(size_t index) {
-        js::ConstArray* arr = consts();
-        MOZ_ASSERT(index < arr->length);
-        return arr->vector[index];
+        return consts()[index];
     }
 
     // The following 3 functions find the static scope just before the
     // execution of the instruction pointed to by pc.
 
     js::Scope* lookupScope(jsbytecode* pc);
 
     js::Scope* innermostScope(jsbytecode* pc);
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -235,25 +235,23 @@ ObjectGroup::useSingletonForAllocationSi
     // All loops in the script will have a try note indicating their boundary.
 
     if (!script->hasTrynotes()) {
         return SingletonObject;
     }
 
     unsigned offset = script->pcToOffset(pc);
 
-    JSTryNote* tn = script->trynotes()->vector;
-    JSTryNote* tnlimit = tn + script->trynotes()->length;
-    for (; tn < tnlimit; tn++) {
-        if (tn->kind != JSTRY_FOR_IN && tn->kind != JSTRY_FOR_OF && tn->kind != JSTRY_LOOP) {
+    for (const JSTryNote& tn : script->trynotes()) {
+        if (tn.kind != JSTRY_FOR_IN && tn.kind != JSTRY_FOR_OF && tn.kind != JSTRY_LOOP) {
             continue;
         }
 
-        unsigned startOffset = script->mainOffset() + tn->start;
-        unsigned endOffset = startOffset + tn->length;
+        unsigned startOffset = script->mainOffset() + tn.start;
+        unsigned endOffset = startOffset + tn.length;
 
         if (offset >= startOffset && offset < endOffset) {
             return GenericObject;
         }
     }
 
     return SingletonObject;
 }
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -705,19 +705,17 @@ Realm::setNewObjectMetadata(JSContext* c
 }
 
 static bool
 AddInnerLazyFunctionsFromScript(JSScript* script, AutoObjectVector& lazyFunctions)
 {
     if (!script->hasObjects()) {
         return true;
     }
-    ObjectArray* objects = script->objects();
-    for (size_t i = 0; i < objects->length; i++) {
-        JSObject* obj = objects->vector[i];
+    for (JSObject* obj : script->objects()) {
         if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
             if (!lazyFunctions.append(obj)) {
                 return false;
             }
         }
     }
     return true;
 }
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -200,23 +200,23 @@ PrintDisplayItemTo(nsDisplayListBuilder*
       aStream << nsPrintfCString(" <a href=\"#%p\">layer=%p</a>", data->GetLayer(), data->GetLayer());
     } else {
       aStream << nsPrintfCString(" layer=0x%p", data->GetLayer());
     }
   }
 #ifdef MOZ_DUMP_PAINTING
   if (aItem->GetType() == DisplayItemType::TYPE_MASK) {
     nsCString str;
-    (static_cast<nsDisplayMask*>(aItem))->PrintEffects(str);
+    (static_cast<nsDisplayMasksAndClipPaths*>(aItem))->PrintEffects(str);
     aStream << str.get();
   }
 
   if (aItem->GetType() == DisplayItemType::TYPE_FILTER) {
     nsCString str;
-    (static_cast<nsDisplayFilter*>(aItem))->PrintEffects(str);
+    (static_cast<nsDisplayFilters*>(aItem))->PrintEffects(str);
     aStream << str.get();
   }
 #endif
   aStream << "\n";
 #ifdef MOZ_DUMP_PAINTING
   if (aDumpHtml && aItem->Painted()) {
     nsCString string(aItem->Name());
     string.Append('-');
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3196,18 +3196,18 @@ nsIFrame::BuildDisplayListForStackingCon
     if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
       // If we are going to create a mask display item, handle opacity effect
       // in that mask display item; Otherwise, take care of opacity in this
       // filter display item.
       bool handleOpacity = !usingMask && !useOpacity;
 
       /* List now emptied, so add the new list to the top. */
       resultList.AppendToTop(
-        MakeDisplayItem<nsDisplayFilter>(aBuilder, this, &resultList,
-                                       handleOpacity));
+        MakeDisplayItem<nsDisplayFilters>(aBuilder, this, &resultList,
+                                          handleOpacity));
     }
 
     if (usingMask) {
       DisplayListClipState::AutoSaveRestore maskClipState(aBuilder);
       // The mask should move with aBuilder->CurrentActiveScrolledRoot(), so
       // that's the ASR we prefer to use for the mask item. However, we can
       // only do this if the mask if clipped with respect to that ASR, because
       // an item always needs to have finite bounds with respect to its ASR.
@@ -3216,22 +3216,22 @@ nsIFrame::BuildDisplayListForStackingCon
       // the mask's contents. That's not entirely crrect, but it satisfies
       // the base requirement of the ASR system (that items have finite bounds
       // wrt. their ASR).
       const ActiveScrolledRoot* maskASR = clipForMask.isSome()
                                         ? aBuilder->CurrentActiveScrolledRoot()
                                         : containerItemASR;
       /* List now emptied, so add the new list to the top. */
       resultList.AppendToTop(
-          MakeDisplayItem<nsDisplayMask>(aBuilder, this, &resultList, !useOpacity,
-                                       maskASR));
+        MakeDisplayItem<nsDisplayMasksAndClipPaths>(aBuilder, this, &resultList,
+                                                    !useOpacity, maskASR));
     }
 
     // Also add the hoisted scroll info items. We need those for APZ scrolling
-    // because nsDisplayMask items can't build active layers.
+    // because nsDisplayMasksAndClipPaths items can't build active layers.
     aBuilder->ExitSVGEffectsContents();
     resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
     if (aCreatedContainerItem) {
       *aCreatedContainerItem = false;
     }
   }
 
   /* If the list is non-empty and there is CSS group opacity without SVG
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -1621,21 +1621,22 @@ protected:
    * add it to |aLayer|'s ancestor mask layers, returning an index into
    * the array of ancestor mask layers. Returns an empty Maybe if
    * |aClip| does not have rounded corners, or if no mask layer could
    * be created.
    */
   Maybe<size_t> SetupMaskLayerForScrolledClip(Layer* aLayer,
                                               const DisplayItemClip& aClip);
 
-  /*
+  /**
    * Create/find a mask layer with suitable size for aMaskItem to paint
    * css-positioned-masking onto.
    */
-  void SetupMaskLayerForCSSMask(Layer* aLayer, nsDisplayMask* aMaskItem);
+  void SetupMaskLayerForCSSMask(Layer* aLayer,
+                                nsDisplayMasksAndClipPaths* aMaskItem);
 
   already_AddRefed<Layer> CreateMaskLayer(
     Layer* aLayer,
     const DisplayItemClip& aClip,
     const Maybe<size_t>& aForAncestorMaskLayer);
 
   /**
    * Get the display port for an AGR.
@@ -4438,22 +4439,23 @@ PaintInactiveLayer(nsDisplayListBuilder*
         Matrix::Translation(-itemVisibleRect.x, -itemVisibleRect.y));
     }
   }
 #endif
   basic->BeginTransaction();
   basic->SetTarget(context);
 
   if (aItem->GetType() == DisplayItemType::TYPE_MASK) {
-    static_cast<nsDisplayMask*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
+    static_cast<nsDisplayMasksAndClipPaths*>(aItem)->
+      PaintAsLayer(aBuilder, aCtx, basic);
     if (basic->InTransaction()) {
       basic->AbortTransaction();
     }
   } else if (aItem->GetType() == DisplayItemType::TYPE_FILTER) {
-    static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
+    static_cast<nsDisplayFilters*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
     if (basic->InTransaction()) {
       basic->AbortTransaction();
     }
   } else {
     basic->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aBuilder);
   }
   FrameLayerBuilder* builder = static_cast<FrameLayerBuilder*>(
     basic->GetUserData(&gLayerManagerLayerBuilder));
@@ -4607,17 +4609,17 @@ SetCSSMaskLayerUserData(Layer* aMaskLaye
 {
   MOZ_ASSERT(aMaskLayer);
 
   aMaskLayer->SetUserData(&gCSSMaskLayerUserData, new CSSMaskLayerUserData());
 }
 
 void
 ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
-                                         nsDisplayMask* aMaskItem)
+                                         nsDisplayMasksAndClipPaths* aMaskItem)
 {
   RefPtr<ImageLayer> maskLayer =
     CreateOrRecycleMaskImageLayerFor(MaskLayerKey(aLayer, Nothing()),
                                      GetCSSMaskLayerUserData,
                                      SetCSSMaskLayerUserData);
   CSSMaskLayerUserData* oldUserData = GetCSSMaskLayerUserData(maskLayer.get());
   MOZ_ASSERT(oldUserData);
 
@@ -5200,17 +5202,18 @@ ContainerState::ProcessDisplayItems(nsDi
             SetupMaskLayerForScrolledClip(ownLayer.get(), scrolledClip));
         }
         ownLayer->SetScrolledClip(Some(scrolledLayerClip));
       }
 
       if (item->GetType() == DisplayItemType::TYPE_MASK) {
         MOZ_ASSERT(itemClip.GetRoundedRectCount() == 0);
 
-        nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
+        nsDisplayMasksAndClipPaths* maskItem =
+          static_cast<nsDisplayMasksAndClipPaths*>(item);
         SetupMaskLayerForCSSMask(ownLayer, maskItem);
 
         if (iter.PeekNext() && iter.PeekNext()->GetType() ==
                                  DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
           // Since we do build a layer for mask, there is no need for this
           // scroll info layer anymore.
           iter.GetNext();
         }
@@ -7736,19 +7739,19 @@ SetMaskLayerUserData(Layer* aMaskLayer)
   aMaskLayer->SetUserData(&gMaskLayerUserData, new MaskLayerUserData());
 }
 
 already_AddRefed<Layer>
 ContainerState::CreateMaskLayer(Layer* aLayer,
                                 const DisplayItemClip& aClip,
                                 const Maybe<size_t>& aForAncestorMaskLayer)
 {
-  // aLayer will never be the container layer created by an nsDisplayMask
-  // because nsDisplayMask propagates the DisplayItemClip to its contents
-  // and is not clipped itself.
+  // aLayer will never be the container layer created by an
+  // nsDisplayMasksAndClipPaths because nsDisplayMasksAndClipPaths propagates
+  // the DisplayItemClip to its contents and is not clipped itself.
   // This assertion will fail if that ever stops being the case.
   MOZ_ASSERT(!aLayer->GetUserData(&gCSSMaskLayerUserData),
              "A layer contains round clips should not have css-mask on it.");
 
   // check if we can re-use the mask layer
   RefPtr<ImageLayer> maskLayer = CreateOrRecycleMaskImageLayerFor(
     MaskLayerKey(aLayer, aForAncestorMaskLayer),
     GetMaskLayerUserData,
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -22,17 +22,17 @@
 #include "nsDisplayItemTypes.h"
 #include "TransformClipNode.h"
 
 class nsDisplayListBuilder;
 class nsDisplayList;
 class nsDisplayItem;
 class gfxContext;
 class nsDisplayItemGeometry;
-class nsDisplayMask;
+class nsDisplayMasksAndClipPaths;
 
 namespace mozilla {
 struct ActiveScrolledRoot;
 struct DisplayItemClipChain;
 namespace layers {
 class ContainerLayer;
 class LayerManager;
 class BasicLayerManager;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -9440,78 +9440,78 @@ nsCharClipDisplayItem::ComputeInvalidati
   if (mVisIStartEdge != geometry->mVisIStartEdge ||
       mVisIEndEdge != geometry->mVisIEndEdge ||
       !oldRect.IsEqualInterior(newRect) ||
       !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
     aInvalidRegion->Or(oldRect, newRect);
   }
 }
 
-nsDisplaySVGEffects::nsDisplaySVGEffects(
+nsDisplayEffectsBase::nsDisplayEffectsBase(
   nsDisplayListBuilder* aBuilder,
   nsIFrame* aFrame,
   nsDisplayList* aList,
   bool aHandleOpacity,
   const ActiveScrolledRoot* aActiveScrolledRoot,
   bool aClearClipChain)
   : nsDisplayWrapList(aBuilder,
                       aFrame,
                       aList,
                       aActiveScrolledRoot,
                       aClearClipChain)
   , mHandleOpacity(aHandleOpacity)
 {
-  MOZ_COUNT_CTOR(nsDisplaySVGEffects);
-}
-
-nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         nsDisplayList* aList,
-                                         bool aHandleOpacity)
+  MOZ_COUNT_CTOR(nsDisplayEffectsBase);
+}
+
+nsDisplayEffectsBase::nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
+                                           nsIFrame* aFrame,
+                                           nsDisplayList* aList,
+                                           bool aHandleOpacity)
   : nsDisplayWrapList(aBuilder, aFrame, aList)
   , mHandleOpacity(aHandleOpacity)
 {
-  MOZ_COUNT_CTOR(nsDisplaySVGEffects);
+  MOZ_COUNT_CTOR(nsDisplayEffectsBase);
 }
 
 nsRegion
-nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                     bool* aSnap) const
+nsDisplayEffectsBase::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                      bool* aSnap) const
 {
   *aSnap = false;
   return nsRegion();
 }
 
 void
-nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder,
-                             const nsRect& aRect,
-                             HitTestState* aState,
-                             nsTArray<nsIFrame*>* aOutFrames)
+nsDisplayEffectsBase::HitTest(nsDisplayListBuilder* aBuilder,
+                              const nsRect& aRect,
+                              HitTestState* aState,
+                              nsTArray<nsIFrame*>* aOutFrames)
 {
   nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
   if (nsSVGIntegrationUtils::HitTestFrameForEffects(
         mFrame, rectCenter - ToReferenceFrame())) {
     mList.HitTest(aBuilder, aRect, aState, aOutFrames);
   }
 }
 
 gfxRect
-nsDisplaySVGEffects::BBoxInUserSpace() const
+nsDisplayEffectsBase::BBoxInUserSpace() const
 {
   return nsSVGUtils::GetBBox(mFrame);
 }
 
 gfxPoint
-nsDisplaySVGEffects::UserSpaceOffset() const
+nsDisplayEffectsBase::UserSpaceOffset() const
 {
   return nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mFrame);
 }
 
 void
-nsDisplaySVGEffects::ComputeInvalidationRegion(
+nsDisplayEffectsBase::ComputeInvalidationRegion(
   nsDisplayListBuilder* aBuilder,
   const nsDisplayItemGeometry* aGeometry,
   nsRegion* aInvalidRegion) const
 {
   auto* geometry = static_cast<const nsDisplaySVGEffectGeometry*>(aGeometry);
   bool snap;
   nsRect bounds = GetBounds(aBuilder, &snap);
   if (geometry->mFrameOffsetToReferenceFrame != ToReferenceFrame() ||
@@ -9523,17 +9523,17 @@ nsDisplaySVGEffects::ComputeInvalidation
     // Invalidations from our inactive layer manager are not enough to catch
     // some of these cases because filters can produce output even if there's
     // nothing in the filter input.
     aInvalidRegion->Or(bounds, geometry->mBounds);
   }
 }
 
 bool
-nsDisplaySVGEffects::ValidateSVGFrame()
+nsDisplayEffectsBase::ValidateSVGFrame()
 {
   const nsIContent* content = mFrame->GetContent();
   bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
   if (hasSVGLayout) {
     nsSVGDisplayableFrame* svgFrame = do_QueryFrame(mFrame);
     if (!svgFrame || !mFrame->GetContent()->IsSVGElement()) {
       NS_ASSERTION(false, "why?");
       return false;
@@ -9628,29 +9628,30 @@ ComputeMaskGeometry(PaintFramesParams& a
     autoSR.SetContext(&ctx);
     ctx.Clip(maskInUserSpace);
   }
 
   IntRect result = ComputeClipExtsInDeviceSpace(ctx);
   aParams.maskRect = result;
 }
 
-nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder,
-                             nsIFrame* aFrame,
-                             nsDisplayList* aList,
-                             bool aHandleOpacity,
-                             const ActiveScrolledRoot* aActiveScrolledRoot)
-  : nsDisplaySVGEffects(aBuilder,
-                        aFrame,
-                        aList,
-                        aHandleOpacity,
-                        aActiveScrolledRoot,
-                        true)
-{
-  MOZ_COUNT_CTOR(nsDisplayMask);
+nsDisplayMasksAndClipPaths::nsDisplayMasksAndClipPaths(
+                              nsDisplayListBuilder* aBuilder,
+                              nsIFrame* aFrame,
+                              nsDisplayList* aList,
+                              bool aHandleOpacity,
+                              const ActiveScrolledRoot* aActiveScrolledRoot)
+  : nsDisplayEffectsBase(aBuilder,
+                         aFrame,
+                         aList,
+                         aHandleOpacity,
+                         aActiveScrolledRoot,
+                         true)
+{
+  MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
 
   nsPresContext* presContext = mFrame->PresContext();
   uint32_t flags =
     aBuilder->GetBackgroundPaintFlags() | nsCSSRendering::PAINTBG_MASK_IMAGE;
   const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask)
   {
     if (!svgReset->mMask.mLayers[i].mImage.IsResolved()) {
@@ -9684,31 +9685,31 @@ CanMergeDisplayMaskFrame(nsIFrame* aFram
   if (aFrame->StyleSVGReset()->HasMask()) {
     return false;
   }
 
   return true;
 }
 
 bool
-nsDisplayMask::CanMerge(const nsDisplayItem* aItem) const
+nsDisplayMasksAndClipPaths::CanMerge(const nsDisplayItem* aItem) const
 {
   // Items for the same content element should be merged into a single
   // compositing group.
   if (!HasDifferentFrame(aItem) || !HasSameTypeAndClip(aItem) ||
       !HasSameContent(aItem)) {
     return false;
   }
 
   return CanMergeDisplayMaskFrame(mFrame) &&
          CanMergeDisplayMaskFrame(aItem->Frame());
 }
 
 bool
-nsDisplayMask::IsValidMask() {
+nsDisplayMasksAndClipPaths::IsValidMask() {
   if (!ValidateSVGFrame()) {
     return false;
   }
 
   if (mFrame->StyleEffects()->mOpacity == 0.0f && mHandleOpacity) {
     return false;
   }
 
@@ -9723,35 +9724,35 @@ nsDisplayMask::IsValidMask() {
   }
 
   return true;
 }
 
 
 
 already_AddRefed<Layer>
-nsDisplayMask::BuildLayer(nsDisplayListBuilder* aBuilder,
-                          LayerManager* aManager,
-                          const ContainerLayerParameters& aContainerParameters)
+nsDisplayMasksAndClipPaths::BuildLayer(nsDisplayListBuilder* aBuilder,
+                                       LayerManager* aManager,
+                                       const ContainerLayerParameters& aContainerParameters)
 {
   if (!IsValidMask()) {
     return nullptr;
   }
 
   RefPtr<ContainerLayer> container =
     aManager->GetLayerBuilder()->BuildContainerLayerFor(
       aBuilder, aManager, mFrame, this, &mList, aContainerParameters, nullptr);
 
   return container.forget();
 }
 
 bool
-nsDisplayMask::PaintMask(nsDisplayListBuilder* aBuilder,
-                         gfxContext* aMaskContext,
-                         bool* aMaskPainted)
+nsDisplayMasksAndClipPaths::PaintMask(nsDisplayListBuilder* aBuilder,
+                                      gfxContext* aMaskContext,
+                                      bool* aMaskPainted)
 {
   MOZ_ASSERT(aMaskContext->GetDrawTarget()->GetFormat() == SurfaceFormat::A8);
 
   imgDrawingParams imgParams(aBuilder->ShouldSyncDecodeImages()
                                ? imgIContainer::FLAG_SYNC_DECODE
                                : imgIContainer::FLAG_SYNC_DECODE_IF_FAST);
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   nsSVGIntegrationUtils::PaintFramesParams params(*aMaskContext,
@@ -9763,43 +9764,43 @@ nsDisplayMask::PaintMask(nsDisplayListBu
                                                   mHandleOpacity,
                                                   imgParams);
   ComputeMaskGeometry(params);
   bool painted = nsSVGIntegrationUtils::PaintMask(params);
   if (aMaskPainted) {
     *aMaskPainted = painted;
   }
 
-  nsDisplayMaskGeometry::UpdateDrawResult(this, imgParams.result);
+  nsDisplayMasksAndClipPathsGeometry::UpdateDrawResult(this, imgParams.result);
 
   return imgParams.result == ImgDrawResult::SUCCESS ||
          imgParams.result == ImgDrawResult::SUCCESS_NOT_COMPLETE;
 }
 
 LayerState
-nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder,
-                             LayerManager* aManager,
-                             const ContainerLayerParameters& aParameters)
+nsDisplayMasksAndClipPaths::GetLayerState(nsDisplayListBuilder* aBuilder,
+                                          LayerManager* aManager,
+                                          const ContainerLayerParameters& aParameters)
 {
   if (CanPaintOnMaskLayer(aManager)) {
     LayerState result = RequiredLayerStateForChildren(
       aBuilder, aManager, aParameters, mList, GetAnimatedGeometryRoot());
     // When we're not active, FrameLayerBuilder will call PaintAsLayer()
     // on us during painting. In that case we don't want a mask layer to
     // be created, because PaintAsLayer() takes care of applying the mask.
     // So we return LAYER_SVG_EFFECTS instead of LAYER_INACTIVE so that
     // FrameLayerBuilder doesn't set a mask layer on our layer.
     return result == LAYER_INACTIVE ? LAYER_SVG_EFFECTS : result;
   }
 
   return LAYER_SVG_EFFECTS;
 }
 
 bool
-nsDisplayMask::CanPaintOnMaskLayer(LayerManager* aManager)
+nsDisplayMasksAndClipPaths::CanPaintOnMaskLayer(LayerManager* aManager)
 {
   if (!nsSVGIntegrationUtils::IsMaskResourceReady(mFrame)) {
     return false;
   }
 
   if (gfxPrefs::DrawMaskLayer()) {
     return false;
   }
@@ -9809,36 +9810,38 @@ nsDisplayMask::CanPaintOnMaskLayer(Layer
   if (GetClip().GetRoundedRectCount() != 0) {
     return false;
   }
 
   return true;
 }
 
 bool
-nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion)
+nsDisplayMasksAndClipPaths::ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                              nsRegion* aVisibleRegion)
 {
   // Our children may be made translucent or arbitrarily deformed so we should
   // not allow them to subtract area from aVisibleRegion.
   nsRegion childrenVisible(GetPaintRect());
   nsRect r = GetPaintRect().Intersect(mList.GetBounds(aBuilder));
   mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
   return true;
 }
 
 void
-nsDisplayMask::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                         const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion) const
-{
-  nsDisplaySVGEffects::ComputeInvalidationRegion(
+nsDisplayMasksAndClipPaths::ComputeInvalidationRegion(
+                              nsDisplayListBuilder* aBuilder,
+                              const nsDisplayItemGeometry* aGeometry,
+                              nsRegion* aInvalidRegion) const
+{
+  nsDisplayEffectsBase::ComputeInvalidationRegion(
     aBuilder, aGeometry, aInvalidRegion);
 
-  auto* geometry = static_cast<const nsDisplayMaskGeometry*>(aGeometry);
+  auto* geometry =
+    static_cast<const nsDisplayMasksAndClipPathsGeometry*>(aGeometry);
   bool snap;
   nsRect bounds = GetBounds(aBuilder, &snap);
 
   if (mFrame->StyleEffects()->mOpacity != geometry->mOpacity ||
       mHandleOpacity != geometry->mHandleOpacity) {
     aInvalidRegion->Or(*aInvalidRegion, bounds);
   }
 
@@ -9863,19 +9866,19 @@ nsDisplayMask::ComputeInvalidationRegion
         aInvalidRegion->Or(*aInvalidRegion, bounds);
         break;
       }
     }
   }
 }
 
 void
-nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder,
-                            gfxContext* aCtx,
-                            LayerManager* aManager)
+nsDisplayMasksAndClipPaths::PaintAsLayer(nsDisplayListBuilder* aBuilder,
+                                         gfxContext* aCtx,
+                                         LayerManager* aManager)
 {
   // Clip the drawing target by mVisibleRect, which contains the visible
   // region of the target frame and its out-of-flow and inflow descendants.
   gfxContext* context = aCtx;
 
   Rect bounds =
     NSRectToRect(GetPaintRect(), mFrame->PresContext()->AppUnitsPerDevPixel());
   bounds.RoundOut();
@@ -9895,23 +9898,24 @@ nsDisplayMask::PaintAsLayer(nsDisplayLis
                                                   imgParams);
 
   ComputeMaskGeometry(params);
 
   nsSVGIntegrationUtils::PaintMaskAndClipPath(params);
 
   context->PopClip();
 
-  nsDisplayMaskGeometry::UpdateDrawResult(this, imgParams.result);
-}
-
-void
-nsDisplayMask::PaintWithContentsPaintCallback(nsDisplayListBuilder* aBuilder,
-                                              gfxContext* aCtx,
-                                              const std::function<void()>& aPaintChildren)
+  nsDisplayMasksAndClipPathsGeometry::UpdateDrawResult(this, imgParams.result);
+}
+
+void
+nsDisplayMasksAndClipPaths::PaintWithContentsPaintCallback(
+                              nsDisplayListBuilder* aBuilder,
+                              gfxContext* aCtx,
+                              const std::function<void()>& aPaintChildren)
 {
   // Clip the drawing target by mVisibleRect, which contains the visible
   // region of the target frame and its out-of-flow and inflow descendants.
   gfxContext* context = aCtx;
 
   Rect bounds =
     NSRectToRect(GetPaintRect(), mFrame->PresContext()->AppUnitsPerDevPixel());
   bounds.RoundOut();
@@ -9931,22 +9935,22 @@ nsDisplayMask::PaintWithContentsPaintCal
                                                   imgParams);
 
   ComputeMaskGeometry(params);
 
   nsSVGIntegrationUtils::PaintMaskAndClipPath(params, aPaintChildren);
 
   context->PopClip();
 
-  nsDisplayMaskGeometry::UpdateDrawResult(this, imgParams.result);
+  nsDisplayMasksAndClipPathsGeometry::UpdateDrawResult(this, imgParams.result);
 }
 
 
 bool
-nsDisplayMask::CreateWebRenderCommands(
+nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
   mozilla::wr::DisplayListBuilder& aBuilder,
   mozilla::wr::IpcResourceUpdateQueue& aResources,
   const StackingContextHelper& aSc,
   mozilla::layers::WebRenderLayerManager* aManager,
   nsDisplayListBuilder* aDisplayListBuilder)
 {
   bool snap;
   float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
@@ -9985,29 +9989,30 @@ nsDisplayMask::CreateWebRenderCommands(
                   /*aClipNodeId: */ &clipId);
     sc = layer.ptr();
     // The whole stacking context will be clipped by us, so no need to have any
     // parent for the children context's clip.
     aManager->CommandBuilder().PushOverrideForASR(GetActiveScrolledRoot(),
                                                   Nothing());
   }
 
-  nsDisplaySVGEffects::CreateWebRenderCommands(
+  nsDisplayEffectsBase::CreateWebRenderCommands(
     aBuilder, aResources, *sc, aManager, aDisplayListBuilder);
 
   if (mask) {
     aManager->CommandBuilder().PopOverrideForASR(GetActiveScrolledRoot());
   }
 
   return true;
 }
 
 Maybe<nsRect>
-nsDisplayMask::GetClipWithRespectToASR(nsDisplayListBuilder* aBuilder,
-                                       const ActiveScrolledRoot* aASR) const
+nsDisplayMasksAndClipPaths::GetClipWithRespectToASR(
+                              nsDisplayListBuilder* aBuilder,
+                              const ActiveScrolledRoot* aASR) const
 {
   if (const DisplayItemClip* clip =
         DisplayItemClipChain::ClipForASR(GetClipChain(), aASR)) {
     return Some(clip->GetClipRect());
   }
   // This item does not have a clip with respect to |aASR|. However, we
   // might still have finite bounds with respect to |aASR|. Check our
   // children.
@@ -10020,17 +10025,17 @@ nsDisplayMask::GetClipWithRespectToASR(n
     MOZ_ASSERT(false, "item should have finite clip with respect to aASR");
   }
 #endif
   return Nothing();
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
-nsDisplayMask::PrintEffects(nsACString& aTo)
+nsDisplayMasksAndClipPaths::PrintEffects(nsACString& aTo)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   SVGObserverUtils::EffectProperties effectProperties =
     SVGObserverUtils::GetEffectProperties(firstFrame);
   nsSVGClipPathFrame* clipPathFrame = effectProperties.GetClipPathFrame();
   bool first = true;
   aTo += " effects=(";
@@ -10061,28 +10066,28 @@ nsDisplayMask::PrintEffects(nsACString& 
       aTo += ", ";
     }
     aTo += "mask";
   }
   aTo += ")";
 }
 #endif
 
-nsDisplayFilter::nsDisplayFilter(nsDisplayListBuilder* aBuilder,
-                                 nsIFrame* aFrame,
-                                 nsDisplayList* aList,
-                                 bool aHandleOpacity)
-  : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity)
+nsDisplayFilters::nsDisplayFilters(nsDisplayListBuilder* aBuilder,
+                                   nsIFrame* aFrame,
+                                   nsDisplayList* aList,
+                                   bool aHandleOpacity)
+  : nsDisplayEffectsBase(aBuilder, aFrame, aList, aHandleOpacity)
   , mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
 {
-  MOZ_COUNT_CTOR(nsDisplayFilter);
+  MOZ_COUNT_CTOR(nsDisplayFilters);
 }
 
 already_AddRefed<Layer>
-nsDisplayFilter::BuildLayer(
+nsDisplayFilters::BuildLayer(
   nsDisplayListBuilder* aBuilder,
   LayerManager* aManager,
   const ContainerLayerParameters& aContainerParameters)
 {
   if (!ValidateSVGFrame()) {
     return nullptr;
   }
 
@@ -10111,90 +10116,90 @@ nsDisplayFilter::BuildLayer(
                                                         this,
                                                         &mList,
                                                         newContainerParameters,
                                                         nullptr);
   return container.forget();
 }
 
 LayerState
-nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder,
-                               LayerManager* aManager,
-                               const ContainerLayerParameters& aParameters)
+nsDisplayFilters::GetLayerState(nsDisplayListBuilder* aBuilder,
+                                LayerManager* aManager,
+                                const ContainerLayerParameters& aParameters)
 {
   return LAYER_SVG_EFFECTS;
 }
 
 bool
-nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                   nsRegion* aVisibleRegion)
+nsDisplayFilters::ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                    nsRegion* aVisibleRegion)
 {
   nsPoint offset = ToReferenceFrame();
   nsRect dirtyRect = nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(
                        mFrame, GetPaintRect() - offset) +
                      offset;
 
   // Our children may be made translucent or arbitrarily deformed so we should
   // not allow them to subtract area from aVisibleRegion.
   nsRegion childrenVisible(dirtyRect);
   nsRect r = dirtyRect.Intersect(
     mList.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot));
   mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
   return true;
 }
 
 void
-nsDisplayFilter::ComputeInvalidationRegion(
+nsDisplayFilters::ComputeInvalidationRegion(
   nsDisplayListBuilder* aBuilder,
   const nsDisplayItemGeometry* aGeometry,
   nsRegion* aInvalidRegion) const
 {
-  nsDisplaySVGEffects::ComputeInvalidationRegion(
+  nsDisplayEffectsBase::ComputeInvalidationRegion(
     aBuilder, aGeometry, aInvalidRegion);
 
-  auto* geometry = static_cast<const nsDisplayFilterGeometry*>(aGeometry);
+  auto* geometry = static_cast<const nsDisplayFiltersGeometry*>(aGeometry);
 
   if (aBuilder->ShouldSyncDecodeImages() &&
       geometry->ShouldInvalidateToSyncDecodeImages()) {
     bool snap;
     nsRect bounds = GetBounds(aBuilder, &snap);
     aInvalidRegion->Or(*aInvalidRegion, bounds);
   }
 }
 
 void
-nsDisplayFilter::PaintAsLayer(nsDisplayListBuilder* aBuilder,
-                              gfxContext* aCtx,
-                              LayerManager* aManager)
+nsDisplayFilters::PaintAsLayer(nsDisplayListBuilder* aBuilder,
+                               gfxContext* aCtx,
+                               LayerManager* aManager)
 {
   imgDrawingParams imgParams(aBuilder->ShouldSyncDecodeImages()
                                ? imgIContainer::FLAG_SYNC_DECODE
                                : imgIContainer::FLAG_SYNC_DECODE_IF_FAST);
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   nsSVGIntegrationUtils::PaintFramesParams params(*aCtx,
                                                   mFrame,
                                                   GetPaintRect(),
                                                   borderArea,
                                                   aBuilder,
                                                   aManager,
                                                   mHandleOpacity,
                                                   imgParams);
   nsSVGIntegrationUtils::PaintFilter(params);
-  nsDisplayFilterGeometry::UpdateDrawResult(this, imgParams.result);
+  nsDisplayFiltersGeometry::UpdateDrawResult(this, imgParams.result);
 }
 
 static float
 ClampStdDeviation(float aStdDeviation)
 {
   // Cap software blur radius for performance reasons.
   return std::min(std::max(0.0f, aStdDeviation), 100.0f);
 }
 
 bool
-nsDisplayFilter::CreateWebRenderCommands(
+nsDisplayFilters::CreateWebRenderCommands(
   mozilla::wr::DisplayListBuilder& aBuilder,
   mozilla::wr::IpcResourceUpdateQueue& aResources,
   const StackingContextHelper& aSc,
   mozilla::layers::WebRenderLayerManager* aManager,
   nsDisplayListBuilder* aDisplayListBuilder)
 {
   // All CSS filters are supported by WebRender. SVG filters are not supported,
   // those use NS_STYLE_FILTER_URL.
@@ -10299,26 +10304,26 @@ nsDisplayFilter::CreateWebRenderCommands
                            Nothing(),
                            &clipId);
 
   // The whole stacking context will be clipped by us, so no need to have any
   // parent for the children context's clip.
   aManager->CommandBuilder().PushOverrideForASR(GetActiveScrolledRoot(),
                                                 Nothing());
 
-  nsDisplaySVGEffects::CreateWebRenderCommands(
+  nsDisplayEffectsBase::CreateWebRenderCommands(
     aBuilder, aResources, sc, aManager, aDisplayListBuilder);
 
   aManager->CommandBuilder().PopOverrideForASR(GetActiveScrolledRoot());
   return true;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
-nsDisplayFilter::PrintEffects(nsACString& aTo)
+nsDisplayFilters::PrintEffects(nsACString& aTo)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   bool first = true;
   aTo += " effects=(";
   if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
     first = false;
     aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -902,17 +902,17 @@ public:
   /**
    * Indicate whether or not we're directly or indirectly under and
    * nsDisplayTransform or SVG foreignObject.
    */
   void SetInTransform(bool aInTransform) { mInTransform = aInTransform; }
 
   /**
    * Returns true if we're currently building a display list that's
-   * under an nsDisplayFilter.
+   * under an nsDisplayFilters.
    */
   bool IsInFilter() const { return mInFilter; }
 
   bool IsInPageSequence() const { return mInPageSequence; }
   void SetInPageSequence(bool aInPage) { mInPageSequence = aInPage; }
 
   /**
    * Return true if we're currently building a display list for a
@@ -6654,41 +6654,44 @@ public:
   int32_t GetChildAppUnitsPerDevPixel() { return mAPD; }
   // Get the app units per dev pixel ratio of the parent document.
   int32_t GetParentAppUnitsPerDevPixel() { return mParentAPD; }
 
 private:
   int32_t mAPD, mParentAPD;
 };
 
-class nsDisplaySVGEffects : public nsDisplayWrapList
+/**
+ * A base class for different effects types.
+ */
+class nsDisplayEffectsBase : public nsDisplayWrapList
 {
 public:
-  nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
-                      nsIFrame* aFrame,
-                      nsDisplayList* aList,
-                      bool aHandleOpacity,
-                      const ActiveScrolledRoot* aActiveScrolledRoot,
-                      bool aClearClipChain = false);
-  nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
-                      nsIFrame* aFrame,
-                      nsDisplayList* aList,
-                      bool aHandleOpacity);
-
-  nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
-                      const nsDisplaySVGEffects& aOther)
+  nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
+                       nsIFrame* aFrame,
+                       nsDisplayList* aList,
+                       bool aHandleOpacity,
+                       const ActiveScrolledRoot* aActiveScrolledRoot,
+                       bool aClearClipChain = false);
+  nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
+                       nsIFrame* aFrame,
+                       nsDisplayList* aList,
+                       bool aHandleOpacity);
+
+  nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
+                       const nsDisplayEffectsBase& aOther)
     : nsDisplayWrapList(aBuilder, aOther)
     , mEffectsBounds(aOther.mEffectsBounds)
     , mHandleOpacity(aOther.mHandleOpacity)
   {
-    MOZ_COUNT_CTOR(nsDisplaySVGEffects);
+    MOZ_COUNT_CTOR(nsDisplayEffectsBase);
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
-  ~nsDisplaySVGEffects() override { MOZ_COUNT_DTOR(nsDisplaySVGEffects); }
+  ~nsDisplayEffectsBase() override { MOZ_COUNT_DTOR(nsDisplayEffectsBase); }
 #endif
 
   nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) const override;
   void HitTest(nsDisplayListBuilder* aBuilder,
                const nsRect& aRect,
                HitTestState* aState,
                nsTArray<nsIFrame*>* aOutFrames) override;
@@ -6712,54 +6715,64 @@ protected:
 
   // relative to mFrame
   nsRect mEffectsBounds;
   // True if we need to handle css opacity in this display item.
   bool mHandleOpacity;
 };
 
 /**
- * A display item to paint a stacking context with mask and clip effects
- * set by the stacking context root frame's style.
+ * A display item to paint a stacking context with 'mask' and 'clip-path'
+ * effects set by the stacking context root frame's style.  The 'mask' and
+ * 'clip-path' properties may both contain multiple masks and clip paths,
+ * respectively.
+ *
+ * Note that 'mask' and 'clip-path' may just contain CSS simple-images and CSS
+ * basic shapes, respectively.  That is, they don't necessarily reference
+ * resources such as SVG 'mask' and 'clipPath' elements.
  */
-class nsDisplayMask : public nsDisplaySVGEffects
+class nsDisplayMasksAndClipPaths : public nsDisplayEffectsBase
 {
 public:
   typedef mozilla::layers::ImageLayer ImageLayer;
 
-  nsDisplayMask(nsDisplayListBuilder* aBuilder,
-                nsIFrame* aFrame,
-                nsDisplayList* aList,
-                bool aHandleOpacity,
-                const ActiveScrolledRoot* aActiveScrolledRoot);
-  nsDisplayMask(nsDisplayListBuilder* aBuilder, const nsDisplayMask& aOther)
-    : nsDisplaySVGEffects(aBuilder, aOther)
+  nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder,
+                             nsIFrame* aFrame,
+                             nsDisplayList* aList,
+                             bool aHandleOpacity,
+                             const ActiveScrolledRoot* aActiveScrolledRoot);
+  nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder,
+                             const nsDisplayMasksAndClipPaths& aOther)
+    : nsDisplayEffectsBase(aBuilder, aOther)
     , mDestRects(aOther.mDestRects)
   {
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
-  ~nsDisplayMask() override { MOZ_COUNT_DTOR(nsDisplayMask); }
+  ~nsDisplayMasksAndClipPaths() override {
+    MOZ_COUNT_DTOR(nsDisplayMasksAndClipPaths);
+  }
 #endif
 
   NS_DISPLAY_DECL_NAME("Mask", TYPE_MASK)
 
   nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override
   {
-    MOZ_COUNT_CTOR(nsDisplayMask);
-    return MakeDisplayItem<nsDisplayMask>(aBuilder, *this);
+    MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
+    return MakeDisplayItem<nsDisplayMasksAndClipPaths>(aBuilder, *this);
   }
 
   bool CanMerge(const nsDisplayItem* aItem) const override;
 
   void Merge(const nsDisplayItem* aItem) override
   {
     nsDisplayWrapList::Merge(aItem);
 
-    const nsDisplayMask* other = static_cast<const nsDisplayMask*>(aItem);
+    const nsDisplayMasksAndClipPaths* other =
+      static_cast<const nsDisplayMasksAndClipPaths*>(aItem);
     mEffectsBounds.UnionRect(mEffectsBounds,
                              other->mEffectsBounds +
                                other->mFrame->GetOffsetTo(mFrame));
   }
 
   already_AddRefed<Layer> BuildLayer(
     nsDisplayListBuilder* aBuilder,
     LayerManager* aManager,
@@ -6769,17 +6782,17 @@ public:
     LayerManager* aManager,
     const ContainerLayerParameters& aParameters) override;
   bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                          nsRegion* aVisibleRegion) override;
 
   nsDisplayItemGeometry* AllocateGeometry(
     nsDisplayListBuilder* aBuilder) override
   {
-    return new nsDisplayMaskGeometry(this, aBuilder);
+    return new nsDisplayMasksAndClipPathsGeometry(this, aBuilder);
   }
 
   void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                  const nsDisplayItemGeometry* aGeometry,
                                  nsRegion* aInvalidRegion) const override;
 #ifdef MOZ_DUMP_PAINTING
   void PrintEffects(nsACString& aTo);
 #endif
@@ -6822,56 +6835,60 @@ private:
   bool CanPaintOnMaskLayer(LayerManager* aManager);
 
   nsTArray<nsRect> mDestRects;
 };
 
 /**
  * A display item to paint a stacking context with filter effects set by the
  * stacking context root frame's style.
+ *
+ * Note that the filters may just be simple CSS filter functions.  That is,
+ * they won't necessarily be references to SVG 'filter' elements.
  */
-class nsDisplayFilter : public nsDisplaySVGEffects
+class nsDisplayFilters : public nsDisplayEffectsBase
 {
 public:
-  nsDisplayFilter(nsDisplayListBuilder* aBuilder,
-                  nsIFrame* aFrame,
-                  nsDisplayList* aList,
-                  bool aHandleOpacity);
-
-  nsDisplayFilter(nsDisplayListBuilder* aBuilder, const nsDisplayFilter& aOther)
-    : nsDisplaySVGEffects(aBuilder, aOther)
+  nsDisplayFilters(nsDisplayListBuilder* aBuilder,
+                   nsIFrame* aFrame,
+                   nsDisplayList* aList,
+                   bool aHandleOpacity);
+
+  nsDisplayFilters(nsDisplayListBuilder* aBuilder,
+                   const nsDisplayFilters& aOther)
+    : nsDisplayEffectsBase(aBuilder, aOther)
     , mEffectsBounds(aOther.mEffectsBounds)
   {
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
-  ~nsDisplayFilter() override { MOZ_COUNT_DTOR(nsDisplayFilter); }
+  ~nsDisplayFilters() override { MOZ_COUNT_DTOR(nsDisplayFilters); }
 #endif
 
   NS_DISPLAY_DECL_NAME("Filter", TYPE_FILTER)
 
   nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override
   {
-    MOZ_COUNT_CTOR(nsDisplayFilter);
-    return MakeDisplayItem<nsDisplayFilter>(aBuilder, *this);
+    MOZ_COUNT_CTOR(nsDisplayFilters);
+    return MakeDisplayItem<nsDisplayFilters>(aBuilder, *this);
   }
 
   bool CanMerge(const nsDisplayItem* aItem) const override
   {
     // Items for the same content element should be merged into a single
     // compositing group.
     return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) &&
            HasSameContent(aItem);
   }
 
   void Merge(const nsDisplayItem* aItem) override
   {
     nsDisplayWrapList::Merge(aItem);
 
-    const nsDisplayFilter* other = static_cast<const nsDisplayFilter*>(aItem);
+    const nsDisplayFilters* other = static_cast<const nsDisplayFilters*>(aItem);
     mEffectsBounds.UnionRect(mEffectsBounds,
                              other->mEffectsBounds +
                                other->mFrame->GetOffsetTo(mFrame));
   }
 
   already_AddRefed<Layer> BuildLayer(
     nsDisplayListBuilder* aBuilder,
     LayerManager* aManager,
@@ -6888,17 +6905,17 @@ public:
   }
 
   bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                          nsRegion* aVisibleRegion) override;
 
   nsDisplayItemGeometry* AllocateGeometry(
     nsDisplayListBuilder* aBuilder) override
   {
-    return new nsDisplayFilterGeometry(this, aBuilder);
+    return new nsDisplayFiltersGeometry(this, aBuilder);
   }
 
   void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                  const nsDisplayItemGeometry* aGeometry,
                                  nsRegion* aInvalidRegion) const override;
 #ifdef MOZ_DUMP_PAINTING
   void PrintEffects(nsACString& aTo);
 #endif
--- a/layout/painting/nsDisplayListInvalidation.cpp
+++ b/layout/painting/nsDisplayListInvalidation.cpp
@@ -120,44 +120,45 @@ nsDisplayBoxShadowOuterGeometry::nsDispl
 void
 nsDisplaySolidColorRegionGeometry::MoveBy(const nsPoint& aOffset)
 {
   nsDisplayItemGeometry::MoveBy(aOffset);
   mRegion.MoveBy(aOffset);
 }
 
 nsDisplaySVGEffectGeometry::nsDisplaySVGEffectGeometry(
-  nsDisplaySVGEffects* aItem,
+  nsDisplayEffectsBase* aItem,
   nsDisplayListBuilder* aBuilder)
   : nsDisplayItemGeometry(aItem, aBuilder)
   , mBBox(aItem->BBoxInUserSpace())
   , mUserSpaceOffset(aItem->UserSpaceOffset())
   , mFrameOffsetToReferenceFrame(aItem->ToReferenceFrame())
 {
 }
 
 void
 nsDisplaySVGEffectGeometry::MoveBy(const nsPoint& aOffset)
 {
   mBounds.MoveBy(aOffset);
   mFrameOffsetToReferenceFrame += aOffset;
 }
 
-nsDisplayMaskGeometry::nsDisplayMaskGeometry(nsDisplayMask* aItem,
-                                             nsDisplayListBuilder* aBuilder)
+nsDisplayMasksAndClipPathsGeometry::nsDisplayMasksAndClipPathsGeometry(
+                                      nsDisplayMasksAndClipPaths* aItem,
+                                      nsDisplayListBuilder* aBuilder)
   : nsDisplaySVGEffectGeometry(aItem, aBuilder)
   , nsImageGeometryMixin(aItem, aBuilder)
   , mDestRects(aItem->GetDestRects())
   , mOpacity(aItem->Frame()->StyleEffects()->mOpacity)
   , mHandleOpacity(aItem->ShouldHandleOpacity())
 {
 }
 
-nsDisplayFilterGeometry::nsDisplayFilterGeometry(nsDisplayFilter* aItem,
-                                                 nsDisplayListBuilder* aBuilder)
+nsDisplayFiltersGeometry::nsDisplayFiltersGeometry(nsDisplayFilters* aItem,
+                                                   nsDisplayListBuilder* aBuilder)
   : nsDisplaySVGEffectGeometry(aItem, aBuilder)
   , nsImageGeometryMixin(aItem, aBuilder)
 {
 }
 
 nsCharClipGeometry::nsCharClipGeometry(nsCharClipDisplayItem* aItem,
                                        nsDisplayListBuilder* aBuilder)
   : nsDisplayItemGenericGeometry(aItem, aBuilder)
--- a/layout/painting/nsDisplayListInvalidation.h
+++ b/layout/painting/nsDisplayListInvalidation.h
@@ -16,19 +16,19 @@
 #include "mozilla/gfx/MatrixFwd.h"
 
 class nsDisplayBackgroundImage;
 class nsCharClipDisplayItem;
 class nsDisplayItem;
 class nsDisplayListBuilder;
 class nsDisplayTableItem;
 class nsDisplayThemedBackground;
-class nsDisplaySVGEffects;
-class nsDisplayMask;
-class nsDisplayFilter;
+class nsDisplayEffectsBase;
+class nsDisplayMasksAndClipPaths;
+class nsDisplayFilters;
 
 namespace mozilla {
 namespace gfx {
 struct Color;
 }
 }
 
 /**
@@ -289,50 +289,51 @@ public:
 
   nsRegion mRegion;
   mozilla::gfx::Color mColor;
 };
 
 class nsDisplaySVGEffectGeometry : public nsDisplayItemGeometry
 {
 public:
-  nsDisplaySVGEffectGeometry(nsDisplaySVGEffects* aItem,
+  nsDisplaySVGEffectGeometry(nsDisplayEffectsBase* aItem,
                              nsDisplayListBuilder* aBuilder);
 
   void MoveBy(const nsPoint& aOffset) override;
 
   gfxRect mBBox;
   gfxPoint mUserSpaceOffset;
   nsPoint mFrameOffsetToReferenceFrame;
 };
 
-class nsDisplayMaskGeometry
+class nsDisplayMasksAndClipPathsGeometry
   : public nsDisplaySVGEffectGeometry
-  , public nsImageGeometryMixin<nsDisplayMaskGeometry>
+  , public nsImageGeometryMixin<nsDisplayMasksAndClipPathsGeometry>
 {
 public:
-  nsDisplayMaskGeometry(nsDisplayMask* aItem, nsDisplayListBuilder* aBuilder);
+  nsDisplayMasksAndClipPathsGeometry(nsDisplayMasksAndClipPaths* aItem,
+                                     nsDisplayListBuilder* aBuilder);
 
   bool InvalidateForSyncDecodeImages() const override
   {
     return ShouldInvalidateToSyncDecodeImages();
   }
 
   nsTArray<nsRect> mDestRects;
   float mOpacity;
   bool mHandleOpacity;
 };
 
-class nsDisplayFilterGeometry
+class nsDisplayFiltersGeometry
   : public nsDisplaySVGEffectGeometry
-  , public nsImageGeometryMixin<nsDisplayFilterGeometry>
+  , public nsImageGeometryMixin<nsDisplayFiltersGeometry>
 {
 public:
-  nsDisplayFilterGeometry(nsDisplayFilter* aItem,
-                          nsDisplayListBuilder* aBuilder);
+  nsDisplayFiltersGeometry(nsDisplayFilters* aItem,
+                           nsDisplayListBuilder* aBuilder);
 
   bool InvalidateForSyncDecodeImages() const override
   {
     return ShouldInvalidateToSyncDecodeImages();
   }
 };
 
 class nsCharClipGeometry : public nsDisplayItemGenericGeometry
--- a/layout/reftests/bugs/1406183-1-ref.html
+++ b/layout/reftests/bugs/1406183-1-ref.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 
-<title>Reference for bug 1406183: ImageLayer inside inactive BasicLayerManager for fallback nsDisplayFilter is drawn at the wrong position</title>
+<title>Reference for bug 1406183: ImageLayer inside inactive BasicLayerManager for fallback nsDisplayFilters is drawn at the wrong position</title>
 
 <style>
 
 body {
   margin: 0;
 }
 
 .outer {
--- a/layout/reftests/bugs/1406183-1.html
+++ b/layout/reftests/bugs/1406183-1.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 
-<title>Testcase for bug 1406183: ImageLayer inside inactive BasicLayerManager for fallback nsDisplayFilter is drawn at the wrong position</title>
+<title>Testcase for bug 1406183: ImageLayer inside inactive BasicLayerManager for fallback nsDisplayFilters is drawn at the wrong position</title>
 
 <style>
 
 body {
   margin: 0;
 }
 
 .outer {
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -65,17 +65,17 @@ random != text-emoji.html text-emoji-not
 == linear-gradient-1b.html linear-gradient-1-ref.html
 
 == zero-dimensions.html zero-dimensions-ref.html
 
 != evenodd-fill-1.html nonzero-fill-1.html
 == evenodd-fill-1.html evenodd-fill-ref.html
 
 == dash-sanity.html data:text/html,<body>Pass
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||azureSkia||skiaContent,0-9,0-470) random-if(Android) fails-if(webrender) == dash-1.html dash-1-ref.svg  # Bug 668412 (really is android-specific, not IPC-specific)
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||azureSkia||skiaContent,0-9,0-470) random-if(Android) == dash-1.html dash-1-ref.svg  # Bug 668412 (really is android-specific, not IPC-specific)
 
 == ctm-sanity.html data:text/html,<body>Pass
 == ctm-singular-sanity.html data:text/html,<body>Pass
 == ctm-1.html ctm-1-ref.html
 
 == 672646-alpha-radial-gradient.html 672646-alpha-radial-gradient-ref.html
 skip-if(verify&&/^Windows\x20NT\x2010\.0/.test(http.oscpu)) == 674003-alpha-radial-gradient-superlum.html 674003-alpha-radial-gradient-superlum-ref.html
 
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -267,17 +267,16 @@ nsSVGRenderingObserverProperty::OnRender
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGFilterObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGFilterObserver)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGFilterObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
-  NS_INTERFACE_MAP_ENTRY(SVGFilterObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFilterObserver)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SVGFilterObserver)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservedElementTracker)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
--- a/layout/svg/SVGObserverUtils.h
+++ b/layout/svg/SVGObserverUtils.h
@@ -285,20 +285,16 @@ public:
 protected:
   virtual ~nsSVGRenderingObserverProperty() {}
 
   virtual void OnRenderingChange() override;
 
   nsSVGFrameReferenceFromProperty mFrameReference;
 };
 
-#define NS_SVGFILTEROBSERVER_IID \
-{ 0x9744ee20, 0x1bcf, 0x4c62, \
- { 0x86, 0x7d, 0xd3, 0x7a, 0x91, 0x60, 0x3e, 0xef } }
-
 /**
  * In a filter chain, there can be multiple SVG reference filters.
  * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
  *
  * This class keeps track of one SVG reference filter in a filter chain.
  * e.g. url(#svg-filter-1)
  *
  * It fires invalidations when the SVG filter element's id changes or when
@@ -322,34 +318,31 @@ public:
   void DetachFromChainObserver() { mFilterObserverList = nullptr; }
 
   /**
    * @return the filter frame, or null if there is no filter frame
    */
   nsSVGFilterFrame *GetFilterFrame();
 
   // nsISupports
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_SVGFILTEROBSERVER_IID)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(SVGFilterObserver)
 
   void Invalidate() { OnRenderingChange(); };
 
 protected:
   virtual ~SVGFilterObserver() {}
 
   // SVGIDRenderingObserver
   virtual void OnRenderingChange() override;
 
 private:
   SVGFilterObserverList* mFilterObserverList;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(SVGFilterObserver, NS_SVGFILTEROBSERVER_IID)
-
 /**
  * This class manages a list of SVGFilterObservers, which correspond to
  * reference to SVG filters in a list of filters in a given 'filter' property.
  * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
  *
  * In the above example, the SVGFilterObserverList will manage two
  * SVGFilterObservers, one for each of the references to SVG filters.  CSS
  * filters like "blur(10px)" don't reference filter elements, so they don't
--- a/layout/svg/nsSVGContainerFrame.cpp
+++ b/layout/svg/nsSVGContainerFrame.cpp
@@ -205,20 +205,16 @@ nsSVGDisplayContainerFrame::RemoveFrame(
   // nsSVGContainerFrame::RemoveFrame doesn't call down into
   // nsContainerFrame::RemoveFrame, so it doesn't call FrameNeedsReflow. We
   // need to schedule a repaint and schedule an update to our overflow rects.
   SchedulePaint();
   PresContext()->RestyleManager()->PostRestyleEvent(
     mContent->AsElement(), nsRestyleHint(0), nsChangeHint_UpdateOverflow);
 
   nsSVGContainerFrame::RemoveFrame(aListID, aOldFrame);
-
-  if (!(GetStateBits() & (NS_FRAME_IS_NONDISPLAY | NS_STATE_IS_OUTER_SVG))) {
-    nsSVGUtils::NotifyAncestorsOfFilterRegionChange(this);
-  }
 }
 
 bool
 nsSVGDisplayContainerFrame::IsSVGTransformed(gfx::Matrix *aOwnTransform,
                                              gfx::Matrix *aFromParentTransform) const
 {
   bool foundTransform = false;
 
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -258,37 +258,16 @@ nsSVGUtils::NeedsReflowSVG(nsIFrame *aFr
   MOZ_ASSERT(aFrame->IsFrameOfType(nsIFrame::eSVG),
              "SVG uses bits differently!");
 
   // The flags we test here may change, hence why we have this separate
   // function.
   return NS_SUBTREE_DIRTY(aFrame);
 }
 
-void
-nsSVGUtils::NotifyAncestorsOfFilterRegionChange(nsIFrame *aFrame)
-{
-  MOZ_ASSERT(!(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG),
-             "Not expecting to be called on the outer SVG Frame");
-
-  aFrame = aFrame->GetParent();
-
-  while (aFrame) {
-    if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)
-      return;
-
-    SVGFilterObserverListForCSSProp* observers =
-      SVGObserverUtils::GetFilterObserverList(aFrame);
-    if (observers) {
-      observers->Invalidate();
-    }
-    aFrame = aFrame->GetParent();
-  }
-}
-
 Size
 nsSVGUtils::GetContextSize(const nsIFrame* aFrame)
 {
   Size size;
 
   MOZ_ASSERT(aFrame->GetContent()->IsSVGElement(), "bad cast");
   const nsSVGElement* element = static_cast<nsSVGElement*>(aFrame->GetContent());
 
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -223,21 +223,16 @@ public:
   static void ScheduleReflowSVG(nsIFrame *aFrame);
 
   /**
    * Returns true if the frame or any of its children need ReflowSVG
    * to be called on them.
    */
   static bool NeedsReflowSVG(nsIFrame *aFrame);
 
-  /*
-   * Update the filter invalidation region for ancestor frames, if relevant.
-   */
-  static void NotifyAncestorsOfFilterRegionChange(nsIFrame *aFrame);
-
   /**
    * Percentage lengths in SVG are resolved against the width/height of the
    * nearest viewport (or its viewBox, if set). This helper returns the size
    * of this "context" for the given frame so that percentage values can be
    * resolved.
    */
   static Size GetContextSize(const nsIFrame* aFrame);
 
--- a/layout/xul/tree/nsITreeView.idl
+++ b/layout/xul/tree/nsITreeView.idl
@@ -140,16 +140,17 @@ interface nsITreeView : nsISupports
   /**
    * Called on the view when a header is clicked.
    */
   void cycleHeader(in TreeColumn col);
 
   /**
    * Should be called from a XUL onselect handler whenever the selection changes.
    */
+  [binaryname(SelectionChangedXPCOM)]
   void selectionChanged();
 
   /**
    * Called on the view when a cell in a non-selectable cycling column (e.g., unread/flag/etc.) is clicked.
    */
   void cycleCell(in long row, in TreeColumn col);
   
   /**
--- a/layout/xul/tree/nsTreeContentView.cpp
+++ b/layout/xul/tree/nsTreeContentView.cpp
@@ -686,17 +686,17 @@ nsTreeContentView::CycleHeader(nsTreeCol
   NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
   CycleHeader(*aCol, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsTreeContentView::SelectionChanged()
+nsTreeContentView::SelectionChangedXPCOM()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTreeContentView::CycleCell(int32_t aRow, nsTreeColumn* aCol)
 {
   return NS_OK;
--- a/layout/xul/tree/nsTreeContentView.h
+++ b/layout/xul/tree/nsTreeContentView.h
@@ -85,17 +85,19 @@ class nsTreeContentView final : public n
     void GetCellValue(int32_t aRow, nsTreeColumn& aColumn, nsAString& aValue,
                       mozilla::ErrorResult& aError);
     void GetCellText(int32_t aRow, nsTreeColumn& aColumn, nsAString& aText,
                      mozilla::ErrorResult& aError);
     void SetTree(mozilla::dom::TreeBoxObject* aTree,
                  mozilla::ErrorResult& aError);
     void ToggleOpenState(int32_t aRow, mozilla::ErrorResult& aError);
     void CycleHeader(nsTreeColumn& aColumn, mozilla::ErrorResult& aError);
-    // XPCOM SelectionChanged() is OK
+    void SelectionChanged()
+    {
+    }
     void CycleCell(int32_t aRow, nsTreeColumn& aColumn)
     {
     }
     bool IsEditable(int32_t aRow, nsTreeColumn& aColumn,
                     mozilla::ErrorResult& aError);
     bool IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
                       mozilla::ErrorResult& aError);
     void SetCellValue(int32_t aRow, nsTreeColumn& aColumn,
new file mode 100644
--- /dev/null
+++ b/media/libyuv/aarch64-windows-noneon.patch
@@ -0,0 +1,14 @@
+diff --git a/media/libyuv/libyuv/libyuv.gyp b/media/libyuv/libyuv/libyuv.gyp
+index 776510b..51ab531 100644
+--- a/media/libyuv/libyuv/libyuv.gyp
++++ b/media/libyuv/libyuv/libyuv.gyp
+@@ -33,7 +33,8 @@
+     'build_msa': 0,
+     'conditions': [
+        ['(target_arch == "armv7" or target_arch == "armv7s" or \
+-       (target_arch == "arm" and arm_version >= 7) or target_arch == "arm64")\
++       (target_arch == "arm" and arm_version >= 7) or \
++       (OS != "win" and target_arch == "arm64")) \
+        and (arm_neon == 1 or arm_neon_optional == 1)', {
+          'build_neon': 1,
+        }],
--- a/media/libyuv/libyuv/libyuv.gyp
+++ b/media/libyuv/libyuv/libyuv.gyp
@@ -28,17 +28,18 @@
     'use_lto%': 0,
     'yuv_disable_asm%': 0,
     'yuv_disable_avx2%': 0,
     'mips_msa%': 0,  # Default to msa off.
     'build_neon': 0,
     'build_msa': 0,
     'conditions': [
        ['(target_arch == "armv7" or target_arch == "armv7s" or \
-       (target_arch == "arm" and arm_version >= 7) or target_arch == "arm64")\
+       (target_arch == "arm" and arm_version >= 7) or \
+       (OS != "win" and target_arch == "arm64")) \
        and (arm_neon == 1 or arm_neon_optional == 1)', {
          'build_neon': 1,
        }],
        ['(target_arch == "mipsel" or target_arch == "mips64el")\
        and (mips_msa == 1)',
        {
          'build_msa': 1,
        }],
old mode 100644
new mode 100755
--- a/media/libyuv/update.py
+++ b/media/libyuv/update.py
@@ -41,16 +41,18 @@ def apply_patches():
     # Patch to fix build errors
     os.system("patch -p3 < fix_build_errors.patch")
     # Patch to make mjpeg printfs optional at build time
     os.system("patch -p3 < make_mjpeg_printfs_optional.patch")
     # Patch to allow disabling of inline ASM and AVX2 code
     os.system("patch -p3 < allow_disabling_asm_avx2.patch")
     # Patch to add H444ToARGB() variant
     os.system("patch -p3 < add_H444ToARGB.patch")
+    # Patch to avoid selecting neon codepaths on AArch64 Windows
+    os.system("patch -p3 < aarch64-windows-noneon.patch")
 
 def update_readme(commit, commitdate):
     with open('README_MOZILLA') as f:
         readme = f.read()
 
     if 'The git commit ID last used to import was ' in readme:
         new_readme = re.sub('The git commit ID last used to import was [v\.a-f0-9]+ \(.+\)',
             'The git commit ID last used to import was %s (%s)' % (commit, commitdate), readme)
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3761,16 +3761,17 @@ Tab.prototype = {
     this.browser.addEventListener("DOMWillOpenModalDialog", this, true);
     this.browser.addEventListener("pagehide", this, true);
     this.browser.addEventListener("pageshow", this, true);
     this.browser.addEventListener("MozApplicationManifest", this, true);
     this.browser.addEventListener("TabPreZombify", this, true);
     this.browser.addEventListener("DOMWindowFocus", this, true);
     this.browser.addEventListener("focusin", this, true);
     this.browser.addEventListener("focusout", this, true);
+    this.browser.addEventListener("TabSelect", this, true);
 
     // Note that the XBL binding is untrusted
     this.browser.addEventListener("VideoBindingAttached", this, true, true);
     this.browser.addEventListener("VideoBindingCast", this, true, true);
 
     Services.obs.addObserver(this, "audioFocusChanged", false);
     Services.obs.addObserver(this, "before-first-paint");
     Services.obs.addObserver(this, "media-playback");
@@ -3899,16 +3900,17 @@ Tab.prototype = {
     this.browser.removeEventListener("DOMWillOpenModalDialog", this, true);
     this.browser.removeEventListener("pagehide", this, true);
     this.browser.removeEventListener("pageshow", this, true);
     this.browser.removeEventListener("MozApplicationManifest", this, true);
     this.browser.removeEventListener("TabPreZombify", this, true);
     this.browser.removeEventListener("DOMWindowFocus", this, true);
     this.browser.removeEventListener("focusin", this, true);
     this.browser.removeEventListener("focusout", this, true);
+    this.browser.removeEventListener("TabSelect", this, true);
 
     this.browser.removeEventListener("VideoBindingAttached", this, true, true);
     this.browser.removeEventListener("VideoBindingCast", this, true, true);
 
     Services.obs.removeObserver(this, "audioFocusChanged");
     Services.obs.removeObserver(this, "before-first-paint");
     Services.obs.removeObserver(this, "media-playback");
 
@@ -4428,38 +4430,48 @@ Tab.prototype = {
           type: "Tab:Select",
           tabID: this.id,
           foreground: true,
         });
         break;
       }
 
       case "focusin": {
-        if (aEvent.composedTarget instanceof HTMLInputElement) {
+        if (BrowserApp.selectedTab === this &&
+            aEvent.composedTarget instanceof HTMLInputElement) {
           this._autoFill.onFocus(aEvent.composedTarget);
         }
         break;
       }
 
       case "focusout": {
-        if (aEvent.composedTarget instanceof HTMLInputElement) {
+        if (BrowserApp.selectedTab === this &&
+            aEvent.composedTarget instanceof HTMLInputElement) {
           this._autoFill.onFocus(null);
         }
         break;
       }
 
+      case "TabSelect": {
+        this._autoFill.clearElements();
+        this._autoFill.scanDocument(this.browser.contentDocument);
+        break;
+      }
+
       case "pagehide": {
-        if (aEvent.target === this.browser.contentDocument) {
+        if (BrowserApp.selectedTab === this &&
+            aEvent.target === this.browser.contentDocument) {
           this._autoFill.clearElements();
         }
         break;
       }
 
       case "pageshow": {
-        if (aEvent.target === this.browser.contentDocument && aEvent.persisted) {
+        if (BrowserApp.selectedTab === this &&
+            aEvent.target === this.browser.contentDocument && aEvent.persisted) {
           this._autoFill.scanDocument(aEvent.target);
         }
 
         // The rest of this only handles pageshow for the top-level document.
         if (aEvent.originalTarget.defaultView != this.browser.contentWindow)
           return;
 
         GlobalEventDispatcher.sendRequest({
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
@@ -772,17 +772,16 @@ public class SessionAccessibility {
     /* package */ void onAutoFillFocus(final GeckoBundle message) {
         if (!Settings.isEnabled() || !(mView instanceof ViewParent) || mAutoFillNodes == null) {
             return;
         }
 
         final int id;
         if (message != null) {
             id = message.getInt("id");
-            mAutoFillNodes.put(id, message);
         } else {
             id = View.NO_ID;
         }
 
         if (DEBUG) {
             Log.d(LOGTAG, "onAutoFillFocus(" + id + ')');
         }
         if (mAutoFillFocusedId == id) {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionTextInput.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionTextInput.java
@@ -729,17 +729,16 @@ public final class SessionTextInput {
     /* package */ void onAutoFillFocus(@Nullable final GeckoBundle message) {
         if (mAutoFillRoots == null) {
             return;
         }
 
         final int id;
         if (message != null) {
             id = message.getInt("id");
-            mAutoFillNodes.put(id, message);
         } else {
             id = View.NO_ID;
         }
 
         if (DEBUG) {
             Log.d(LOGTAG, "onAutoFillFocus(" + id + ')');
         }
         if (mAutoFillFocusedId == id) {
--- a/mobile/android/modules/geckoview/GeckoViewAutoFill.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewAutoFill.jsm
@@ -62,17 +62,17 @@ class GeckoViewAutoFill {
       task.arm();
       if (!this._autoFillTasks) {
         this._autoFillTasks = new WeakMap();
       }
       this._autoFillTasks.set(aFormLike.rootElement, task);
       return;
     }
 
-    debug `Adding auto-fill ${aFormLike}`;
+    debug `Adding auto-fill ${aFormLike.rootElement.tagName}`;
 
     this._autoFillTasks.delete(aFormLike.rootElement);
 
     if (!this._autoFillInfos) {
       this._autoFillInfos = new WeakMap();
       this._autoFillElements = new Map();
     }
 
--- a/security/manager/pki/nsASN1Tree.cpp
+++ b/security/manager/pki/nsASN1Tree.cpp
@@ -335,17 +335,17 @@ nsNSSASN1Tree::ToggleOpenState(int32_t i
 
 NS_IMETHODIMP
 nsNSSASN1Tree::CycleHeader(nsTreeColumn*)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::SelectionChanged()
+nsNSSASN1Tree::SelectionChangedXPCOM()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsNSSASN1Tree::CycleCell(int32_t, nsTreeColumn*)
 {
   return NS_OK;
--- a/security/manager/ssl/nsCertTree.cpp
+++ b/security/manager/ssl/nsCertTree.cpp
@@ -1122,17 +1122,17 @@ nsCertTree::ToggleOpenState(int32_t inde
 
 NS_IMETHODIMP
 nsCertTree::CycleHeader(nsTreeColumn* col)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::SelectionChanged()
+nsCertTree::SelectionChangedXPCOM()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsCertTree::CycleCell(int32_t row, nsTreeColumn* col)
 {
   return NS_OK;
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -914,16 +914,19 @@ set_config('ENABLE_MARIONETTE', marionet
 # Turn off geckodriver for build configs we don't handle yet,
 # but allow --enable-geckodriver to override when compile environment is available.
 # --disable-tests implies disabling geckodriver.
 
 @depends('--enable-tests', target, cross_compiling, hazard_analysis, asan)
 def geckodriver_default(enable_tests, target, cross_compile, hazard, asan):
     if not enable_tests:
         return False
+    # geckodriver depends on winapi 0.2.8, which doesn't work with AArch64.
+    if target.os == 'WINNT' and target.cpu == 'aarch64':
+        return False
     if hazard or target.os == 'Android' or (asan and cross_compile):
         return False
     return True
 
 option('--enable-geckodriver', default=geckodriver_default,
        when='--enable-compile-environment',
        help='Build geckodriver')
 
--- a/toolkit/mozapps/installer/package-name.mk
+++ b/toolkit/mozapps/installer/package-name.mk
@@ -18,20 +18,20 @@ ifndef MOZ_PKG_PLATFORM
 MOZ_PKG_PLATFORM := $(TARGET_OS)-$(TARGET_CPU)
 
 ifeq ($(MOZ_BUILD_APP),mobile/android)
 MOZ_PKG_PLATFORM := android-$(TARGET_CPU)
 endif
 
 # TARGET_OS/TARGET_CPU may be unintuitive, so we hardcode some special formats
 ifeq ($(OS_ARCH),WINNT)
-ifeq ($(TARGET_CPU),x86_64)
+ifeq ($(CPU_ARCH),x86)
+MOZ_PKG_PLATFORM := win32
+else
 MOZ_PKG_PLATFORM := win64
-else
-MOZ_PKG_PLATFORM := win32
 endif
 endif
 ifeq ($(OS_ARCH),Darwin)
 MOZ_PKG_PLATFORM := mac
 endif
 ifeq ($(TARGET_OS),linux-gnu)
 MOZ_PKG_PLATFORM := linux-$(TARGET_CPU)
 endif
--- a/xpcom/reflect/xptcall/md/win32/xptcstubs_asm_aarch64.asm
+++ b/xpcom/reflect/xptcall/md/win32/xptcstubs_asm_aarch64.asm
@@ -34,16 +34,17 @@ NFPREGS EQU 8
 	add         sp, sp, #128 ; 8*(NGPREGS+NFPREGS)
 	ldp         x29, x30, [sp],#16
 	ret
 	ENDP
 
 
 	MACRO
 	STUBENTRY $functionname, $paramcount
+	EXPORT |$functionname|
 |$functionname| PROC
 	mov	w17, $paramcount
 	b	SharedStub
 	ENDP
 	MEND
 
     STUBENTRY ?Stub3@nsXPTCStubBase@@UEAA?AW4nsresult@@XZ, 3
     STUBENTRY ?Stub4@nsXPTCStubBase@@UEAA?AW4nsresult@@XZ, 4
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -846,16 +846,19 @@ nsThread::ShutdownInternal(bool aSync)
     return nullptr;
   }
 
   MaybeRemoveFromThreadList();
 
   NotNull<nsThread*> currentThread =
     WrapNotNull(nsThreadManager::get().GetCurrentThread());
 
+  MOZ_DIAGNOSTIC_ASSERT(currentThread->EventQueue(),
+                        "Shutdown() may only be called from an XPCOM thread");
+
   nsAutoPtr<nsThreadShutdownContext>& context =
     *currentThread->mRequestedShutdownContexts.AppendElement();
   context = new nsThreadShutdownContext(WrapNotNull(this), currentThread, aSync);
 
   // Set mShutdownContext and wake up the thread in case it is waiting for
   // events to process.
   nsCOMPtr<nsIRunnable> event =
     new nsThreadShutdownEvent(WrapNotNull(this), WrapNotNull(context.get()));