From 141cdeeed6af092d88c10cbd1a963a13bfecbe3b Mon Sep 17 00:00:00 2001
From: Sandor Molnar <smolnar@mozilla.com>
Date: Thu, 22 Sep 2022 19:13:01 +0300
Subject: [PATCH] Backed out 11 changesets (bug 1788969, bug 1782400, bug
 1777145) for causing bp-hybri bustages. CLOSED TREE

Backed out changeset 8acabb924ef7 (bug 1782400)
Backed out changeset e3d452e99f77 (bug 1782400)
Backed out changeset 5727bc4895d2 (bug 1777145)
Backed out changeset cf375034e2b8 (bug 1777145)
Backed out changeset a50fd5608d8d (bug 1777145)
Backed out changeset f24853cacd7a (bug 1777145)
Backed out changeset c714f3a35b11 (bug 1777145)
Backed out changeset 56682c253427 (bug 1788969)
Backed out changeset edaf37ffc49d (bug 1788969)
Backed out changeset d19caa9f062b (bug 1788969)
Backed out changeset 18b26912dc03 (bug 1788969)
---
 dom/base/nsJSEnvironment.cpp                  |   1 -
 dom/bindings/Codegen.py                       | 280 ++++++-----------
 dom/bindings/Configuration.py                 |  20 +-
 dom/bindings/IterableIterator.cpp             | 284 +++--------------
 dom/bindings/IterableIterator.h               | 287 +++++-------------
 dom/bindings/ToJSValue.h                      |  28 --
 dom/bindings/parser/WebIDL.py                 |  42 +--
 .../test/TestInterfaceAsyncIterableDouble.cpp |  63 ++--
 .../test/TestInterfaceAsyncIterableDouble.h   |  28 +-
 .../TestInterfaceAsyncIterableDoubleUnion.cpp |  64 ++--
 .../TestInterfaceAsyncIterableDoubleUnion.h   |  29 +-
 .../test/TestInterfaceAsyncIterableSingle.cpp |  89 +++---
 .../test/TestInterfaceAsyncIterableSingle.h   |  38 +--
 ...stInterfaceAsyncIterableSingleWithArgs.cpp |  64 +---
 ...TestInterfaceAsyncIterableSingleWithArgs.h |  30 +-
 dom/bindings/test/test_async_iterable.html    | 117 +------
 dom/broadcastchannel/BroadcastChannel.cpp     |   1 -
 dom/cache/Cache.cpp                           |   1 -
 dom/cache/CacheStorage.h                      |   2 -
 dom/cache/TypeUtils.cpp                       |   1 -
 dom/fs/api/FileSystemDirectoryHandle.cpp      |  27 +-
 dom/fs/api/FileSystemDirectoryHandle.h        |  14 +-
 .../FileSystemDirectoryIteratorFactory.cpp    | 108 +++++--
 .../api/TestFileSystemDirectoryHandle.cpp     |  36 ++-
 dom/ipc/SharedMap.cpp                         |   1 -
 dom/notification/Notification.cpp             |   1 -
 dom/promise/Promise-inl.h                     |  64 ++--
 dom/promise/Promise.h                         |  16 +-
 .../gtest/ThenWithCycleCollectedArgsJS.cpp    |  78 -----
 dom/serviceworkers/ServiceWorkerContainer.cpp |   1 -
 ...stInterfaceJSMaplikeSetlikeIterable.webidl |   6 -
 dom/workers/WorkerPrivate.cpp                 |   1 -
 dom/worklet/Worklet.cpp                       |   1 -
 mfbt/Tuple.h                                  |   4 +-
 mfbt/tests/TestTuple.cpp                      |  54 ----
 .../extensions/webrequest/StreamFilter.cpp    |   1 -
 36 files changed, 598 insertions(+), 1284 deletions(-)

diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp
index 3ef29154057e7..f889808fe8fb7 100644
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -63,7 +63,6 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/FetchUtil.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/SerializedStackHolder.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index acbf49e9e7c6b..a2c3ebcc1406e 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -35,6 +35,7 @@ from Configuration import (
     getAllTypes,
     Descriptor,
     MemberIsLegacyUnforgeable,
+    iteratorNativeType,
 )
 
 AUTOGENERATED_WARNING_COMMENT = (
@@ -1854,9 +1855,6 @@ class CGAbstractMethod(CGThing):
     arguments.
 
     canRunScript should be True to generate a MOZ_CAN_RUN_SCRIPT annotation.
-
-    signatureOnly should be True to only declare the signature (either in
-                  the header, or if static is True in the cpp file).
     """
 
     def __init__(
@@ -1870,7 +1868,6 @@ class CGAbstractMethod(CGThing):
         static=False,
         templateArgs=None,
         canRunScript=False,
-        signatureOnly=False,
     ):
         CGThing.__init__(self)
         self.descriptor = descriptor
@@ -1882,7 +1879,6 @@ class CGAbstractMethod(CGThing):
         self.static = static
         self.templateArgs = templateArgs
         self.canRunScript = canRunScript
-        self.signatureOnly = signatureOnly
 
     def _argstring(self, declare):
         return ", ".join([a.declare() if declare else a.define() for a in self.args])
@@ -1906,7 +1902,9 @@ class CGAbstractMethod(CGThing):
         maybeNewline = " " if self.inline else "\n"
         return " ".join(decorators) + maybeNewline
 
-    def signature(self):
+    def declare(self):
+        if self.inline:
+            return self._define(True)
         return "%s%s%s(%s);\n" % (
             self._template(),
             self._decorators(),
@@ -1914,13 +1912,6 @@ class CGAbstractMethod(CGThing):
             self._argstring(True),
         )
 
-    def declare(self):
-        if self.static:
-            return ""
-        if self.inline:
-            return self._define(True)
-        return self.signature()
-
     def indent_body(self, body):
         """
         Indent the code returned by self.definition_body(). Most classes
@@ -1937,12 +1928,7 @@ class CGAbstractMethod(CGThing):
         )
 
     def define(self):
-        if self.signatureOnly:
-            if self.static:
-                # self.static makes us not output anything in the header, so output the signature here.
-                return self.signature()
-            return ""
-        return "" if (self.inline and not self.static) else self._define()
+        return "" if self.inline else self._define()
 
     def definition_prologue(self, fromDeclare):
         error_reporting_label = self.error_reporting_label()
@@ -2027,6 +2013,10 @@ class CGAbstractStaticMethod(CGAbstractMethod):
             canRunScript=canRunScript,
         )
 
+    def declare(self):
+        # We only have implementation
+        return ""
+
 
 class CGAbstractClassHook(CGAbstractStaticMethod):
     """
@@ -2050,6 +2040,14 @@ class CGAbstractClassHook(CGAbstractStaticMethod):
         assert False  # Override me!
 
 
+class CGGetJSClassMethod(CGAbstractMethod):
+    def __init__(self, descriptor):
+        CGAbstractMethod.__init__(self, descriptor, "GetJSClass", "const JSClass*", [])
+
+    def definition_body(self):
+        return "return sClass.ToJSClass();\n"
+
+
 class CGAddPropertyHook(CGAbstractClassHook):
     """
     A hook for addProperty, used to preserve our wrapper from GC.
@@ -3566,7 +3564,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
     """
 
     def __init__(
-        self, descriptor, properties, haveUnscopables, haveLegacyWindowAliases, static
+        self, descriptor, properties, haveUnscopables, haveLegacyWindowAliases
     ):
         args = [
             Argument("JSContext*", "aCx"),
@@ -3575,7 +3573,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
             Argument("bool", "aDefineOnGlobal"),
         ]
         CGAbstractMethod.__init__(
-            self, descriptor, "CreateInterfaceObjects", "void", args, static=static
+            self, descriptor, "CreateInterfaceObjects", "void", args
         )
         self.properties = properties
         self.haveUnscopables = haveUnscopables
@@ -3948,7 +3946,7 @@ class CGGetProtoObjectHandleMethod(CGAbstractMethod):
     A method for getting the interface prototype object.
     """
 
-    def __init__(self, descriptor, static, signatureOnly=False):
+    def __init__(self, descriptor):
         CGAbstractMethod.__init__(
             self,
             descriptor,
@@ -3956,8 +3954,6 @@ class CGGetProtoObjectHandleMethod(CGAbstractMethod):
             "JS::Handle<JSObject*>",
             [Argument("JSContext*", "aCx")],
             inline=True,
-            static=static,
-            signatureOnly=signatureOnly,
         )
 
     def definition_body(self):
@@ -4308,7 +4304,7 @@ class CGDeserializer(CGAbstractMethod):
         )
 
 
-def CreateBindingJSObject(descriptor):
+def CreateBindingJSObject(descriptor, properties):
     objDecl = "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor.nativeType
 
     # We don't always need to root obj, but there are a variety
@@ -4501,17 +4497,9 @@ def CopyUnforgeablePropertiesToInstance(descriptor, failureCode):
 
 
 def AssertInheritanceChain(descriptor):
-    # We can skip the reinterpret_cast check for the descriptor's nativeType
-    # if aObject is a pointer of that type.
-    asserts = fill(
-        """
-        static_assert(std::is_same_v<decltype(aObject), ${nativeType}*>);
-        """,
-        nativeType=descriptor.nativeType,
-    )
+    asserts = ""
     iface = descriptor.interface
-    while iface.parent:
-        iface = iface.parent
+    while iface:
         desc = descriptor.getDescriptor(iface.identifier.name)
         asserts += (
             "MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
@@ -4519,6 +4507,7 @@ def AssertInheritanceChain(descriptor):
             '           "Multiple inheritance for %s is broken.");\n'
             % (desc.nativeType, desc.nativeType, desc.nativeType)
         )
+        iface = iface.parent
     asserts += "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
     return asserts
 
@@ -4544,26 +4533,16 @@ def InitMemberSlots(descriptor, failureCode):
     )
 
 
-def DeclareProto(descriptor, noGivenProto=False):
+def DeclareProto(descriptor):
     """
     Declare the canonicalProto and proto we have for our wrapping operation.
     """
-    getCanonical = dedent(
+    preamble = dedent(
         """
-        JS::Handle<JSObject*> ${canonicalProto} = GetProtoObjectHandle(aCx);
-        if (!${canonicalProto}) {
+        JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
+        if (!canonicalProto) {
           return false;
         }
-        """
-    )
-
-    if noGivenProto:
-        return fill(getCanonical, canonicalProto="proto")
-
-    getCanonical = fill(getCanonical, canonicalProto="canonicalProto")
-
-    preamble = getCanonical + dedent(
-        """
         JS::Rooted<JSObject*> proto(aCx);
         """
     )
@@ -4600,9 +4579,11 @@ def DeclareProto(descriptor, noGivenProto=False):
 class CGWrapWithCacheMethod(CGAbstractMethod):
     """
     Create a wrapper JSObject for a given native that implements nsWrapperCache.
+
+    properties should be a PropertyArrays instance.
     """
 
-    def __init__(self, descriptor):
+    def __init__(self, descriptor, properties):
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [
             Argument("JSContext*", "aCx"),
@@ -4612,6 +4593,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
             Argument("JS::MutableHandle<JSObject*>", "aReflector"),
         ]
         CGAbstractMethod.__init__(self, descriptor, "Wrap", "bool", args)
+        self.properties = properties
 
     def definition_body(self):
         failureCode = dedent(
@@ -4695,7 +4677,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
             nativeType=self.descriptor.nativeType,
             assertInheritance=AssertInheritanceChain(self.descriptor),
             declareProto=DeclareProto(self.descriptor),
-            createObject=CreateBindingJSObject(self.descriptor),
+            createObject=CreateBindingJSObject(self.descriptor, self.properties),
             unforgeable=CopyUnforgeablePropertiesToInstance(
                 self.descriptor, failureCode
             ),
@@ -4736,48 +4718,29 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
     """
     Create a wrapper JSObject for a given native that does not implement
     nsWrapperCache.
+
+    properties should be a PropertyArrays instance.
     """
 
-    def __init__(self, descriptor, static=False, signatureOnly=False):
+    def __init__(self, descriptor, properties):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
-        self.noGivenProto = (
-            descriptor.interface.isIteratorInterface()
-            or descriptor.interface.isAsyncIteratorInterface()
-        )
         args = [
             Argument("JSContext*", "aCx"),
             Argument(descriptor.nativeType + "*", "aObject"),
+            Argument("JS::Handle<JSObject*>", "aGivenProto"),
+            Argument("JS::MutableHandle<JSObject*>", "aReflector"),
         ]
-        if not self.noGivenProto:
-            args.append(Argument("JS::Handle<JSObject*>", "aGivenProto"))
-        args.append(Argument("JS::MutableHandle<JSObject*>", "aReflector"))
-        CGAbstractMethod.__init__(
-            self,
-            descriptor,
-            "Wrap",
-            "bool",
-            args,
-            static=static,
-            signatureOnly=signatureOnly,
-        )
+        CGAbstractMethod.__init__(self, descriptor, "Wrap", "bool", args)
+        self.properties = properties
 
     def definition_body(self):
         failureCode = "return false;\n"
 
-        declareProto = DeclareProto(self.descriptor, noGivenProto=self.noGivenProto)
-        if self.noGivenProto:
-            assertGivenProto = ""
-        else:
-            assertGivenProto = dedent(
-                """
-                MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
-                """
-            )
         return fill(
             """
             $*{assertions}
-            $*{assertGivenProto}
+            MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
 
             JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
             $*{declareProto}
@@ -4792,9 +4755,8 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
             return true;
             """,
             assertions=AssertInheritanceChain(self.descriptor),
-            assertGivenProto=assertGivenProto,
-            declareProto=declareProto,
-            createObject=CreateBindingJSObject(self.descriptor),
+            declareProto=DeclareProto(self.descriptor),
+            createObject=CreateBindingJSObject(self.descriptor, self.properties),
             unforgeable=CopyUnforgeablePropertiesToInstance(
                 self.descriptor, failureCode
             ),
@@ -5343,7 +5305,7 @@ class CastableObjectUnwrapper:
                 }
                 """,
                 exceptionCode=exceptionCode,
-                **self.substitution,
+                **self.substitution
             )
         else:
             self.substitution["codeOnFailure"] = codeOnFailure
@@ -5363,7 +5325,7 @@ class CastableObjectUnwrapper:
               }
             }
             """,
-            **substitution,
+            **substitution
         )
 
 
@@ -9581,6 +9543,7 @@ class CGPerSignatureCall(CGThing):
                 cgThings.append(
                     CGIterableMethodGenerator(
                         descriptor,
+                        idlNode.maplikeOrSetlikeOrIterable,
                         idlNode.identifier.name,
                         self.getArgumentNames(),
                     )
@@ -12849,7 +12812,7 @@ class CGUnionStruct(CGThing):
                     mType = e${name};
                     return mValue.m${name}.SetValue(${ctorArgs});
                     """,
-                    **vars,
+                    **vars
                 )
 
                 # bodyInHeader must be false for return values because they own
@@ -12916,7 +12879,7 @@ class CGUnionStruct(CGThing):
                 mValue.m${name}.Destroy();
                 mType = eUninitialized;
                 """,
-                **vars,
+                **vars
             )
             methods.append(
                 ClassMethod(
@@ -12934,7 +12897,7 @@ class CGUnionStruct(CGThing):
                 MOZ_RELEASE_ASSERT(Is${name}(), "Wrong type!");
                 return mValue.m${name}.Value();
                 """,
-                **vars,
+                **vars
             )
             # The non-const version of GetAs* returns our internal type
             getterReturnType = "%s&" % vars["structType"]
@@ -13281,7 +13244,7 @@ class CGUnionConversionStruct(CGThing):
                     mUnion.mType = mUnion.e${name};
                     return mUnion.mValue.m${name}.SetValue(${ctorArgs});
                     """,
-                    **vars,
+                    **vars
                 )
                 methods.append(
                     ClassMethod(
@@ -16393,52 +16356,19 @@ class CGDescriptor(CGThing):
 
         self._deps = descriptor.interface.getDeps()
 
-        iteratorCGThings = None
-        if (
-            descriptor.interface.isIterable()
-            and descriptor.interface.maplikeOrSetlikeOrIterable.isPairIterator()
-        ) or descriptor.interface.isAsyncIterable():
-            # We need the Wrap function when using the [Async]IterableIterator type, so we want to declare it before we need it. We don't really want to expose it in the header file, so we make it static too.
-            iteratorCGThings = []
-            itr_iface = (
-                descriptor.interface.maplikeOrSetlikeOrIterable.iteratorType.inner
-            )
-            iteratorDescriptor = descriptor.getDescriptor(itr_iface.identifier.name)
-            iteratorCGThings.append(
-                CGWrapNonWrapperCacheMethod(
-                    iteratorDescriptor, static=True, signatureOnly=True
-                )
-            )
-            iteratorCGThings = CGList(
-                (CGIndenter(t, declareOnly=True) for t in iteratorCGThings), "\n"
-            )
-            iteratorCGThings = CGWrapper(iteratorCGThings, pre="\n", post="\n")
-            iteratorCGThings = CGWrapper(
-                CGNamespace(
-                    toBindingNamespace(iteratorDescriptor.name), iteratorCGThings
-                ),
-                post="\n",
-            )
-
         cgThings = []
-
-        isIteratorInterface = (
-            descriptor.interface.isIteratorInterface()
-            or descriptor.interface.isAsyncIteratorInterface()
+        cgThings.append(
+            CGGeneric(declare="typedef %s NativeType;\n" % descriptor.nativeType)
         )
-        if not isIteratorInterface:
+        parent = descriptor.interface.parent
+        if parent:
             cgThings.append(
-                CGGeneric(declare="typedef %s NativeType;\n" % descriptor.nativeType)
-            )
-            parent = descriptor.interface.parent
-            if parent:
-                cgThings.append(
-                    CGGeneric(
-                        "static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
-                        '              "Can\'t inherit from an interface with a different ownership model.");\n'
-                        % toBindingNamespace(descriptor.parentPrototypeName)
-                    )
+                CGGeneric(
+                    "static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
+                    '              "Can\'t inherit from an interface with a different ownership model.");\n'
+                    % toBindingNamespace(descriptor.parentPrototypeName)
                 )
+            )
 
         defaultToJSONMethod = None
         needCrossOriginPropertyArrays = False
@@ -16641,19 +16571,12 @@ class CGDescriptor(CGThing):
                 cgThings.append(CGSerializer(descriptor))
                 cgThings.append(CGDeserializer(descriptor))
 
-            # CGDOMProxyJSClass/CGDOMJSClass need GetProtoObjectHandle, but we don't want to export it for the iterator interfaces, so declare it here.
-            if isIteratorInterface:
-                cgThings.append(
-                    CGGetProtoObjectHandleMethod(
-                        descriptor, static=True, signatureOnly=True
-                    )
-                )
-
             if descriptor.proxy:
                 cgThings.append(CGDOMJSProxyHandlerDefiner(handlerThing))
                 cgThings.append(CGDOMProxyJSClass(descriptor))
             else:
                 cgThings.append(CGDOMJSClass(descriptor))
+                cgThings.append(CGGetJSClassMethod(descriptor))
 
             if descriptor.interface.hasMembersInSlots():
                 cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
@@ -16662,12 +16585,10 @@ class CGDescriptor(CGThing):
                 assert descriptor.wrapperCache
                 cgThings.append(CGWrapGlobalMethod(descriptor, properties))
             elif descriptor.wrapperCache:
-                cgThings.append(CGWrapWithCacheMethod(descriptor))
+                cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
                 cgThings.append(CGWrapMethod(descriptor))
             else:
-                cgThings.append(
-                    CGWrapNonWrapperCacheMethod(descriptor, static=isIteratorInterface)
-                )
+                cgThings.append(CGWrapNonWrapperCacheMethod(descriptor, properties))
 
         # If we're not wrappercached, we don't know how to clear our
         # cached values, since we can't get at the JSObject.
@@ -16726,11 +16647,7 @@ class CGDescriptor(CGThing):
         # CGDOMJSClass and unscopables, if any.
         cgThings.append(
             CGCreateInterfaceObjectsMethod(
-                descriptor,
-                properties,
-                haveUnscopables,
-                haveLegacyWindowAliases,
-                static=isIteratorInterface,
+                descriptor, properties, haveUnscopables, haveLegacyWindowAliases
             )
         )
 
@@ -16740,11 +16657,8 @@ class CGDescriptor(CGThing):
             descriptor.interface.hasInterfacePrototypeObject()
             and not descriptor.hasOrdinaryObjectPrototype
         ):
-            cgThings.append(
-                CGGetProtoObjectHandleMethod(descriptor, static=isIteratorInterface)
-            )
+            cgThings.append(CGGetProtoObjectHandleMethod(descriptor))
             if descriptor.interface.hasChildInterfaces():
-                assert not isIteratorInterface
                 cgThings.append(CGGetProtoObjectMethod(descriptor))
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGGetConstructorObjectHandleMethod(descriptor))
@@ -16756,10 +16670,9 @@ class CGDescriptor(CGThing):
 
         cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
         cgThings = CGWrapper(cgThings, pre="\n", post="\n")
-        cgThings = CGWrapper(
+        self.cgRoot = CGWrapper(
             CGNamespace(toBindingNamespace(descriptor.name), cgThings), post="\n"
         )
-        self.cgRoot = CGList([iteratorCGThings, cgThings], "\n")
 
     def declare(self):
         return self.cgRoot.declare()
@@ -18377,11 +18290,8 @@ class CGBindingRoot(CGThing):
         bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = any(
             d.isObject() for t in unionTypes for d in t.flatMemberTypes
         )
-        bindingHeaders["mozilla/dom/IterableIterator.h"] = any(
-            (
-                d.interface.isIteratorInterface()
-                and d.interface.maplikeOrSetlikeOrIterable.isPairIterator()
-            )
+        bindingDeclareHeaders["mozilla/dom/IterableIterator.h"] = any(
+            d.interface.isIteratorInterface()
             or d.interface.isAsyncIteratorInterface()
             or d.interface.isIterable()
             or d.interface.isAsyncIterable()
@@ -22280,7 +22190,7 @@ class CGIterableMethodGenerator(CGGeneric):
     using CGCallGenerator.
     """
 
-    def __init__(self, descriptor, methodName, args):
+    def __init__(self, descriptor, iterable, methodName, args):
         if methodName == "forEach":
             assert len(args) == 2
 
@@ -22319,51 +22229,43 @@ class CGIterableMethodGenerator(CGGeneric):
             return
 
         if descriptor.interface.isIterable():
-            assert descriptor.interface.maplikeOrSetlikeOrIterable.isPairIterator()
             assert len(args) == 0
 
-            wrap = f"{descriptor.interface.identifier.name}Iterator_Binding::Wrap"
-            iterClass = f"mozilla::dom::binding_detail::WrappableIterableIterator<{descriptor.nativeType}, &{wrap}>"
+            binding = descriptor.interface.identifier.name + "Iterator_Binding"
+            init = ""
         else:
-            needReturnMethod = toStringBool(
-                descriptor.interface.maplikeOrSetlikeOrIterable.getExtendedAttribute(
-                    "GenerateReturnMethod"
-                )
-                is not None
-            )
-            wrap = f"{descriptor.interface.identifier.name}AsyncIterator_Binding::Wrap"
-            iterClass = f"mozilla::dom::binding_detail::WrappableAsyncIterableIterator<{descriptor.nativeType}, {needReturnMethod}, &{wrap}>"
+            assert descriptor.interface.isAsyncIterable()
 
-        createIterator = fill(
-            """
-            typedef ${iterClass} itrType;
-            RefPtr<itrType> result(new itrType(self,
-                                               itrType::IteratorType::${itrMethod}));
-            """,
-            iterClass=iterClass,
-            itrMethod=methodName.title(),
-        )
-
-        if descriptor.interface.isAsyncIterable():
-            args.append("initError")
-            createIterator = fill(
+            binding = descriptor.interface.identifier.name + "AsyncIterator_Binding"
+            init = fill(
                 """
-                $*{createIterator}
                 {
                   ErrorResult initError;
-                  self->InitAsyncIteratorData(result->Data(), itrType::IteratorType::${itrMethod}, ${args});
+                  self->InitAsyncIterator(result.get(), ${args}initError);
                   if (initError.MaybeSetPendingException(cx, "Asynchronous iterator initialization steps for ${ifaceName} failed")) {
                     return false;
                   }
                 }
                 """,
-                createIterator=createIterator,
-                itrMethod=methodName.title(),
-                args=", ".join(args),
+                args="".join(a + ", " for a in args),
                 ifaceName=descriptor.interface.identifier.name,
             )
-
-        CGGeneric.__init__(self, createIterator)
+        CGGeneric.__init__(
+            self,
+            fill(
+                """
+                typedef ${iterClass} itrType;
+                RefPtr<itrType> result(new itrType(self,
+                                                   itrType::IteratorType::${itrMethod},
+                                                   &${binding}::Wrap));
+                $*{init}
+                """,
+                iterClass=iteratorNativeType(descriptor),
+                itrMethod=methodName.title(),
+                binding=binding,
+                init=init,
+            ),
+        )
 
 
 def getObservableArrayBackingObject(descriptor, attr, errorReturn="return false;\n"):
diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py
index c1eb524b407f3..dd317fecf6a79 100644
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -13,13 +13,6 @@ from collections import defaultdict
 autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
 
 
-def toStringBool(arg):
-    """
-    Converts IDL/Python Boolean (True/False) to C++ Boolean (true/false)
-    """
-    return str(not not arg).lower()
-
-
 class DescriptorProvider:
     """
     A way of getting descriptors for interface names.  Subclasses must
@@ -764,8 +757,6 @@ class Descriptor(DescriptorProvider):
         if name in self.implicitJSContext:
             attrs.append("implicitJSContext")
         if member.isMethod():
-            if self.interface.isAsyncIteratorInterface() and name == "next":
-                attrs.append("implicitJSContext")
             # JSObject-returning [NewObject] methods must be fallible,
             # since they have to (fallibly) allocate the new JSObject.
             if member.getExtendedAttribute("NewObject"):
@@ -1059,16 +1050,7 @@ def iteratorNativeType(descriptor):
     assert iterableDecl.isPairIterator() or descriptor.interface.isAsyncIterable()
     if descriptor.interface.isIterable():
         return "mozilla::dom::IterableIterator<%s>" % descriptor.nativeType
-    needReturnMethod = toStringBool(
-        descriptor.interface.maplikeOrSetlikeOrIterable.getExtendedAttribute(
-            "GenerateReturnMethod"
-        )
-        is not None
-    )
-    return "mozilla::dom::binding_detail::AsyncIterableIteratorNative<%s, %s>" % (
-        descriptor.nativeType,
-        needReturnMethod,
-    )
+    return "mozilla::dom::AsyncIterableIterator<%s>" % descriptor.nativeType
 
 
 def findInnermostType(t):
diff --git a/dom/bindings/IterableIterator.cpp b/dom/bindings/IterableIterator.cpp
index e2183865f7e1f..438d581786d15 100644
--- a/dom/bindings/IterableIterator.cpp
+++ b/dom/bindings/IterableIterator.cpp
@@ -5,7 +5,6 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/IterableIterator.h"
-#include "mozilla/dom/Promise-inl.h"
 
 namespace mozilla::dom {
 
@@ -16,8 +15,8 @@ namespace mozilla::dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IterableIteratorBase)
 
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(IterableIteratorBase, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(IterableIteratorBase, Release)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(IterableIteratorBase)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(IterableIteratorBase)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IterableIteratorBase)
   tmp->TraverseHelper(cb);
@@ -27,9 +26,12 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IterableIteratorBase)
   tmp->UnlinkHelper();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-namespace iterator_utils {
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IterableIteratorBase)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
 
-void DictReturn(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
+namespace iterator_utils {
+void DictReturn(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
                 bool aDone, JS::Handle<JS::Value> aValue, ErrorResult& aRv) {
   RootedDictionary<IterableKeyOrValueResult> dict(aCx);
   dict.mDone = aDone;
@@ -39,16 +41,6 @@ void DictReturn(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
-  aResult.set(dictValue);
-}
-
-void DictReturn(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
-                bool aDone, JS::Handle<JS::Value> aValue, ErrorResult& aRv) {
-  JS::Rooted<JS::Value> dictValue(aCx);
-  DictReturn(aCx, &dictValue, aDone, aValue, aRv);
-  if (aRv.Failed()) {
-    return;
-  }
   aResult.set(&dictValue.toObject());
 }
 
@@ -75,249 +67,43 @@ void KeyAndValueReturn(JSContext* aCx, JS::Handle<JS::Value> aKey,
   aResult.set(&dictValue.toObject());
 }
 
-}  // namespace iterator_utils
-
-namespace binding_detail {
-
-static already_AddRefed<Promise> PromiseOrErr(
-    Result<RefPtr<Promise>, nsresult>&& aResult, ErrorResult& aError) {
-  if (aResult.isErr()) {
-    aError.Throw(aResult.unwrapErr());
-    return nullptr;
-  }
-
-  return aResult.unwrap().forget();
-}
-
-already_AddRefed<Promise> AsyncIterableNextImpl::NextSteps(
-    JSContext* aCx, AsyncIterableIteratorBase* aObject,
-    nsIGlobalObject* aGlobalObject, ErrorResult& aRv) {
-  // 2. If object’s is finished is true, then:
-  if (aObject->mIsFinished) {
-    // 1. Let result be CreateIterResultObject(undefined, true).
-    JS::Rooted<JS::Value> dict(aCx);
-    iterator_utils::DictReturn(aCx, &dict, true, JS::UndefinedHandleValue, aRv);
-    if (aRv.Failed()) {
-      return Promise::CreateRejectedWithErrorResult(aGlobalObject, aRv);
-    }
+void ResolvePromiseForFinished(JSContext* aCx, Promise* aPromise,
+                               ErrorResult& aRv) {
+  MOZ_ASSERT(aPromise);
 
-    // 2. Perform ! Call(nextPromiseCapability.[[Resolve]], undefined,
-    //    «result»).
-    // 3. Return nextPromiseCapability.[[Promise]].
-    return Promise::Resolve(aGlobalObject, aCx, dict, aRv);
-  }
-
-  // 4. Let nextPromise be the result of getting the next iteration result with
-  //    object’s target and object.
-  RefPtr<Promise> nextPromise = GetNextResult(aRv);
-
-  // 5. Let fulfillSteps be the following steps, given next:
-  auto fulfillSteps = [](JSContext* aCx, JS::Handle<JS::Value> aNext,
-                         ErrorResult& aRv,
-                         const RefPtr<AsyncIterableIteratorBase>& aObject,
-                         const nsCOMPtr<nsIGlobalObject>& aGlobalObject)
-      -> already_AddRefed<Promise> {
-    // 1. Set object’s ongoing promise to null.
-    aObject->mOngoingPromise = nullptr;
-
-    // 2. If next is end of iteration, then:
-    JS::Rooted<JS::Value> dict(aCx);
-    if (aNext.isMagic(binding_details::END_OF_ITERATION)) {
-      // 1. Set object’s is finished to true.
-      aObject->mIsFinished = true;
-      // 2. Return CreateIterResultObject(undefined, true).
-      iterator_utils::DictReturn(aCx, &dict, true, JS::UndefinedHandleValue,
-                                 aRv);
-      if (aRv.Failed()) {
-        return nullptr;
-      }
-    } else {
-      // 3. Otherwise, if interface has a pair asynchronously iterable
-      // declaration:
-      //   1. Assert: next is a value pair.
-      //   2. Return the iterator result for next and kind.
-      // 4. Otherwise:
-      //   1. Assert: interface has a value asynchronously iterable declaration.
-      //   2. Assert: next is a value of the type that appears in the
-      //   declaration.
-      //   3. Let value be next, converted to an ECMAScript value.
-      //   4. Return CreateIterResultObject(value, false).
-      iterator_utils::DictReturn(aCx, &dict, false, aNext, aRv);
-      if (aRv.Failed()) {
-        return nullptr;
-      }
-    }
-    // Note that ThenCatchWithCycleCollectedArgs expects a Promise, so
-    // we use Promise::Resolve here. The specs do convert this to a
-    // promise too at another point, but the end result should be the
-    // same.
-    return Promise::Resolve(aGlobalObject, aCx, dict, aRv);
-  };
-  // 7. Let rejectSteps be the following steps, given reason:
-  auto rejectSteps = [](JSContext* aCx, JS::Handle<JS::Value> aReason,
-                        ErrorResult& aRv,
-                        const RefPtr<AsyncIterableIteratorBase>& aObject,
-                        const nsCOMPtr<nsIGlobalObject>& aGlobalObject) {
-    // 1. Set object’s ongoing promise to null.
-    aObject->mOngoingPromise = nullptr;
-    // 2. Set object’s is finished to true.
-    aObject->mIsFinished = true;
-    // 3. Throw reason.
-    return Promise::Reject(aGlobalObject, aCx, aReason, aRv);
-  };
-  // 9. Perform PerformPromiseThen(nextPromise, onFulfilled, onRejected,
-  //    nextPromiseCapability).
-  Result<RefPtr<Promise>, nsresult> result =
-      nextPromise->ThenCatchWithCycleCollectedArgs(
-          std::move(fulfillSteps), std::move(rejectSteps), RefPtr{aObject},
-          nsCOMPtr{aGlobalObject});
-
-  // 10. Return nextPromiseCapability.[[Promise]].
-  return PromiseOrErr(std::move(result), aRv);
-}
-
-already_AddRefed<Promise> AsyncIterableNextImpl::Next(
-    JSContext* aCx, AsyncIterableIteratorBase* aObject,
-    nsISupports* aGlobalObject, ErrorResult& aRv) {
-  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(aGlobalObject);
-
-  // 3.7.10.2. Asynchronous iterator prototype object
-  // …
-  // 10. If ongoingPromise is not null, then:
-  if (aObject->mOngoingPromise) {
-    // 1. Let afterOngoingPromiseCapability be
-    //    ! NewPromiseCapability(%Promise%).
-    // 2. Let onSettled be CreateBuiltinFunction(nextSteps, « »).
-
-    // aObject is the same object as 'this', so it's fine to capture 'this'
-    // without taking a strong reference, because we already take a strong
-    // reference to it through aObject.
-    auto onSettled = [this](JSContext* aCx, JS::Handle<JS::Value> aValue,
-                            ErrorResult& aRv,
-                            const RefPtr<AsyncIterableIteratorBase>& aObject,
-                            const nsCOMPtr<nsIGlobalObject>& aGlobalObject) {
-      return NextSteps(aCx, aObject, aGlobalObject, aRv);
-    };
-
-    // 3. Perform PerformPromiseThen(ongoingPromise, onSettled, onSettled,
-    //    afterOngoingPromiseCapability).
-    Result<RefPtr<Promise>, nsresult> afterOngoingPromise =
-        aObject->mOngoingPromise->ThenCatchWithCycleCollectedArgs(
-            onSettled, onSettled, RefPtr{aObject}, std::move(globalObject));
-    if (afterOngoingPromise.isErr()) {
-      aRv.Throw(afterOngoingPromise.unwrapErr());
-      return nullptr;
-    }
-
-    // 4. Set object’s ongoing promise to
-    //    afterOngoingPromiseCapability.[[Promise]].
-    aObject->mOngoingPromise = afterOngoingPromise.unwrap().forget();
-  } else {
-    // 11. Otherwise:
-    //   1. Set object’s ongoing promise to the result of running nextSteps.
-    aObject->mOngoingPromise = NextSteps(aCx, aObject, globalObject, aRv);
+  JS::Rooted<JSObject*> dict(aCx);
+  DictReturn(aCx, &dict, true, JS::UndefinedHandleValue, aRv);
+  if (aRv.Failed()) {
+    return;
   }
-
-  // 12. Return object’s ongoing promise.
-  return do_AddRef(aObject->mOngoingPromise);
+  aPromise->MaybeResolve(dict);
 }
 
-already_AddRefed<Promise> AsyncIterableReturnImpl::ReturnSteps(
-    JSContext* aCx, AsyncIterableIteratorBase* aObject,
-    nsIGlobalObject* aGlobalObject, JS::Handle<JS::Value> aValue,
-    ErrorResult& aRv) {
-  // 2. If object’s is finished is true, then:
-  if (aObject->mIsFinished) {
-    // 1. Let result be CreateIterResultObject(value, true).
-    JS::Rooted<JS::Value> dict(aCx);
-    iterator_utils::DictReturn(aCx, &dict, true, aValue, aRv);
-    if (aRv.Failed()) {
-      return Promise::CreateRejectedWithErrorResult(aGlobalObject, aRv);
-    }
+void ResolvePromiseWithKeyOrValue(JSContext* aCx, Promise* aPromise,
+                                  JS::Handle<JS::Value> aKeyOrValue,
+                                  ErrorResult& aRv) {
+  MOZ_ASSERT(aPromise);
 
-    // 2. Perform ! Call(returnPromiseCapability.[[Resolve]], undefined,
-    //    «result»).
-    // 3. Return returnPromiseCapability.[[Promise]].
-    return Promise::Resolve(aGlobalObject, aCx, dict, aRv);
+  JS::Rooted<JSObject*> dict(aCx);
+  DictReturn(aCx, &dict, false, aKeyOrValue, aRv);
+  if (aRv.Failed()) {
+    return;
   }
-
-  // 3. Set object’s is finished to true.
-  aObject->mIsFinished = true;
-
-  // 4. Return the result of running the asynchronous iterator return algorithm
-  // for interface, given object’s target, object, and value.
-  return GetReturnPromise(aCx, aValue, aRv);
+  aPromise->MaybeResolve(dict);
 }
 
-already_AddRefed<Promise> AsyncIterableReturnImpl::Return(
-    JSContext* aCx, AsyncIterableIteratorBase* aObject,
-    nsISupports* aGlobalObject, JS::Handle<JS::Value> aValue,
-    ErrorResult& aRv) {
-  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(aGlobalObject);
+void ResolvePromiseWithKeyAndValue(JSContext* aCx, Promise* aPromise,
+                                   JS::Handle<JS::Value> aKey,
+                                   JS::Handle<JS::Value> aValue,
+                                   ErrorResult& aRv) {
+  MOZ_ASSERT(aPromise);
 
-  // 3.7.10.2. Asynchronous iterator prototype object
-  // …
-  RefPtr<Promise> returnStepsPromise;
-  // 11. If ongoingPromise is not null, then:
-  if (aObject->mOngoingPromise) {
-    // 1. Let afterOngoingPromiseCapability be
-    //    ! NewPromiseCapability(%Promise%).
-    // 2. Let onSettled be CreateBuiltinFunction(returnSteps, « »).
-
-    // aObject is the same object as 'this', so it's fine to capture 'this'
-    // without taking a strong reference, because we already take a strong
-    // reference to it through aObject.
-    auto onSettled = [this](JSContext* aCx, JS::Handle<JS::Value> aValue,
-                            ErrorResult& aRv,
-                            const RefPtr<AsyncIterableIteratorBase>& aObject,
-                            const nsCOMPtr<nsIGlobalObject>& aGlobalObject,
-                            JS::Handle<JS::Value> aVal) {
-      return ReturnSteps(aCx, aObject, aGlobalObject, aVal, aRv);
-    };
-
-    // 3. Perform PerformPromiseThen(ongoingPromise, onSettled, onSettled,
-    //    afterOngoingPromiseCapability).
-    Result<RefPtr<Promise>, nsresult> afterOngoingPromise =
-        aObject->mOngoingPromise->ThenCatchWithCycleCollectedArgsJS(
-            onSettled, onSettled,
-            std::make_tuple(RefPtr{aObject}, nsCOMPtr{globalObject}),
-            std::make_tuple(aValue));
-    if (afterOngoingPromise.isErr()) {
-      aRv.Throw(afterOngoingPromise.unwrapErr());
-      return nullptr;
-    }
-
-    // 4. Set returnStepsPromise to afterOngoingPromiseCapability.[[Promise]].
-    returnStepsPromise = afterOngoingPromise.unwrap().forget();
-  } else {
-    // 12. Otherwise:
-    //   1. Set returnStepsPromise to the result of running returnSteps.
-    returnStepsPromise = ReturnSteps(aCx, aObject, globalObject, aValue, aRv);
+  JS::Rooted<JSObject*> dict(aCx);
+  KeyAndValueReturn(aCx, aKey, aValue, &dict, aRv);
+  if (aRv.Failed()) {
+    return;
   }
-
-  // 13. Let fulfillSteps be the following steps:
-  auto onFullFilled = [](JSContext* aCx, JS::Handle<JS::Value>,
-                         ErrorResult& aRv,
-                         const nsCOMPtr<nsIGlobalObject>& aGlobalObject,
-                         JS::Handle<JS::Value> aVal) {
-    // 1. Return CreateIterResultObject(value, true).
-    JS::Rooted<JS::Value> dict(aCx);
-    iterator_utils::DictReturn(aCx, &dict, true, aVal, aRv);
-    return Promise::Resolve(aGlobalObject, aCx, dict, aRv);
-  };
-
-  // 14. Let onFulfilled be CreateBuiltinFunction(fulfillSteps, « »).
-  // 15. Perform PerformPromiseThen(returnStepsPromise, onFulfilled, undefined,
-  // returnPromiseCapability).
-  Result<RefPtr<Promise>, nsresult> returnPromise =
-      returnStepsPromise->ThenWithCycleCollectedArgsJS(
-          onFullFilled, std::make_tuple(std::move(globalObject)),
-          std::make_tuple(aValue));
-
-  // 16. Return returnPromiseCapability.[[Promise]].
-  return PromiseOrErr(std::move(returnPromise), aRv);
+  aPromise->MaybeResolve(dict);
 }
-
-}  // namespace binding_detail
-
+}  // namespace iterator_utils
 }  // namespace mozilla::dom
diff --git a/dom/bindings/IterableIterator.h b/dom/bindings/IterableIterator.h
index 2ca32750f3d6b..2534fbbecc88d 100644
--- a/dom/bindings/IterableIterator.h
+++ b/dom/bindings/IterableIterator.h
@@ -31,7 +31,6 @@
 #include "js/TypeDecls.h"
 #include "js/Value.h"
 #include "nsISupports.h"
-#include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/dom/IterableIteratorBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/RootedDictionary.h"
@@ -40,19 +39,7 @@
 
 namespace mozilla::dom {
 
-namespace binding_details {
-
-// JS::MagicValue(END_OF_ITERATION) is the value we use for
-// https://webidl.spec.whatwg.org/#end-of-iteration. It shouldn't be returned to
-// JS, because AsyncIterableIteratorBase::NextSteps will detect it and will
-// return the result of CreateIterResultObject(undefined, true) instead
-// (discarding the magic value).
-static const JSWhyMagic END_OF_ITERATION = JS_GENERIC_MAGIC;
-
-}  // namespace binding_details
-
 namespace iterator_utils {
-
 void DictReturn(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
                 bool aDone, JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
@@ -60,23 +47,23 @@ void KeyAndValueReturn(JSContext* aCx, JS::Handle<JS::Value> aKey,
                        JS::Handle<JS::Value> aValue,
                        JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv);
 
-inline void ResolvePromiseForFinished(Promise* aPromise) {
-  aPromise->MaybeResolve(JS::MagicValue(binding_details::END_OF_ITERATION));
-}
+void ResolvePromiseForFinished(JSContext* aCx, Promise* aPromise,
+                               ErrorResult& aRv);
 
-template <typename Key, typename Value>
-void ResolvePromiseWithKeyAndValue(Promise* aPromise, const Key& aKey,
-                                   const Value& aValue) {
-  aPromise->MaybeResolve(MakeTuple(aKey, aValue));
-}
+void ResolvePromiseWithKeyOrValue(JSContext* aCx, Promise* aPromise,
+                                  JS::Handle<JS::Value> aKeyOrValue,
+                                  ErrorResult& aRv);
 
+void ResolvePromiseWithKeyAndValue(JSContext* aCx, Promise* aPromise,
+                                   JS::Handle<JS::Value> aKey,
+                                   JS::Handle<JS::Value> aValue,
+                                   ErrorResult& aRv);
 }  // namespace iterator_utils
 
-class IterableIteratorBase {
+class IterableIteratorBase : public nsISupports {
  public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(IterableIteratorBase)
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(IterableIteratorBase)
-
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(IterableIteratorBase)
   typedef enum { Keys = 0, Values, Entries } IteratorType;
 
   IterableIteratorBase() = default;
@@ -127,11 +114,20 @@ bool CallIterableGetter(JSContext* aCx,
 }
 
 template <typename T>
-class IterableIterator : public IterableIteratorBase {
+class IterableIterator final : public IterableIteratorBase {
  public:
-  IterableIterator(T* aIterableObj, IteratorType aIteratorType)
-      : mIterableObj(aIterableObj), mIteratorType(aIteratorType), mIndex(0) {
+  typedef bool (*WrapFunc)(JSContext* aCx, IterableIterator<T>* aObject,
+                           JS::Handle<JSObject*> aGivenProto,
+                           JS::MutableHandle<JSObject*> aReflector);
+
+  explicit IterableIterator(T* aIterableObj, IteratorType aIteratorType,
+                            WrapFunc aWrapFunc)
+      : mIterableObj(aIterableObj),
+        mIteratorType(aIteratorType),
+        mWrapFunc(aWrapFunc),
+        mIndex(0) {
     MOZ_ASSERT(mIterableObj);
+    MOZ_ASSERT(mWrapFunc);
   }
 
   bool GetKeyAtIndex(JSContext* aCx, uint32_t aIndex,
@@ -189,6 +185,11 @@ class IterableIterator : public IterableIteratorBase {
     ++mIndex;
   }
 
+  bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
+                  JS::MutableHandle<JSObject*> aObj) {
+    return (*mWrapFunc)(aCx, this, aGivenProto, aObj);
+  }
+
  protected:
   virtual ~IterableIterator() = default;
 
@@ -205,215 +206,85 @@ class IterableIterator : public IterableIteratorBase {
   RefPtr<T> mIterableObj;
   // Tells whether this is a key, value, or entries iterator.
   IteratorType mIteratorType;
+  // Function pointer to binding-type-specific Wrap() call for this iterator.
+  WrapFunc mWrapFunc;
   // Current index of iteration.
   uint32_t mIndex;
 };
 
-namespace binding_detail {
-
-class AsyncIterableNextImpl;
-class AsyncIterableReturnImpl;
-
-}  // namespace binding_detail
-
-class AsyncIterableIteratorBase : public IterableIteratorBase {
+template <typename T>
+class AsyncIterableIterator final : public IterableIteratorBase,
+                                    public SupportsWeakPtr {
  public:
-  IteratorType GetIteratorType() { return mIteratorType; }
+  typedef bool (*WrapFunc)(JSContext* aCx, AsyncIterableIterator<T>* aObject,
+                           JS::Handle<JSObject*> aGivenProto,
+                           JS::MutableHandle<JSObject*> aReflector);
+
+  explicit AsyncIterableIterator(T* aIterableObj, IteratorType aIteratorType,
+                                 WrapFunc aWrapFunc)
+      : mIterableObj(aIterableObj),
+        mIteratorType(aIteratorType),
+        mWrapFunc(aWrapFunc) {
+    MOZ_ASSERT(mIterableObj);
+    MOZ_ASSERT(mWrapFunc);
+  }
 
- protected:
-  explicit AsyncIterableIteratorBase(IteratorType aIteratorType)
-      : mIteratorType(aIteratorType) {}
+  void SetData(void* aData) { mData = aData; }
 
- private:
-  friend class binding_detail::AsyncIterableNextImpl;
-  friend class binding_detail::AsyncIterableReturnImpl;
+  void* GetData() { return mData; }
 
-  // 3.7.10.1. Default asynchronous iterator objects
-  // Target is in AsyncIterableIterator
-  // Kind
-  IteratorType mIteratorType;
-  // Ongoing promise
-  RefPtr<Promise> mOngoingPromise;
-  // Is finished
-  bool mIsFinished = false;
-};
-
-template <typename T>
-class AsyncIterableIterator : public AsyncIterableIteratorBase {
- private:
-  using IteratorData = typename T::IteratorData;
+  IteratorType GetIteratorType() { return mIteratorType; }
 
- public:
-  AsyncIterableIterator(T* aIterableObj, IteratorType aIteratorType)
-      : AsyncIterableIteratorBase(aIteratorType), mIterableObj(aIterableObj) {
-    MOZ_ASSERT(mIterableObj);
+  void Next(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
+            ErrorResult& aRv) {
+    RefPtr<Promise> promise = mIterableObj->GetNextPromise(aCx, this, aRv);
+    if (!promise) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return;
+    }
+    aResult.set(promise->PromiseObj());
   }
 
-  IteratorData& Data() { return mData; }
-
- protected:
-  // We'd prefer to use ImplCycleCollectionTraverse/ImplCycleCollectionUnlink on
-  // the iterator data, but unfortunately that doesn't work because it's
-  // dependent on the template parameter. Instead we detect if the data
-  // structure has Traverse and Unlink functions and call those.
-  template <typename Data>
-  auto TraverseData(Data& aData, nsCycleCollectionTraversalCallback& aCallback,
-                    int) -> decltype(aData.Traverse(aCallback)) {
-    return aData.Traverse(aCallback);
+  bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
+                  JS::MutableHandle<JSObject*> aObj) {
+    return (*mWrapFunc)(aCx, this, aGivenProto, aObj);
   }
-  template <typename Data>
-  void TraverseData(Data& aData, nsCycleCollectionTraversalCallback& aCallback,
-                    double) {}
 
-  template <typename Data>
-  auto UnlinkData(Data& aData, int) -> decltype(aData.Unlink()) {
-    return aData.Unlink();
+ protected:
+  virtual ~AsyncIterableIterator() {
+    // As long as iterable object does not hold strong ref to its iterators,
+    // iterators will not be added to CC graph, thus make sure
+    // DestroyAsyncIterator still take place.
+    if (mIterableObj) {
+      mIterableObj->DestroyAsyncIterator(this);
+    }
   }
-  template <typename Data>
-  void UnlinkData(Data& aData, double) {}
 
   // Since we're templated on a binding, we need to possibly CC it, but can't do
   // that through macros. So it happens here.
+  // DestroyAsyncIterator is expected to assume that its AsyncIterableIterator
+  // does not need access to mData anymore. AsyncIterator does not manage mData
+  // so it should be release and null out explicitly.
   void UnlinkHelper() final {
-    AsyncIterableIterator<T>* tmp = this;
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(mIterableObj);
-    UnlinkData(tmp->mData, 0);
+    mIterableObj->DestroyAsyncIterator(this);
+    mIterableObj = nullptr;
   }
 
   virtual void TraverseHelper(nsCycleCollectionTraversalCallback& cb) override {
     AsyncIterableIterator<T>* tmp = this;
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIterableObj);
-    TraverseData(tmp->mData, cb, 0);
   }
 
-  // 3.7.10.1. Default asynchronous iterator objects
-  // Target
+  // Binding Implementation object that we're iterating over.
   RefPtr<T> mIterableObj;
-  // Kind
-  // Ongoing promise
-  // Is finished
-  // See AsyncIterableIteratorBase
-
+  // Tells whether this is a key, value, or entries iterator.
+  IteratorType mIteratorType;
+  // Function pointer to binding-type-specific Wrap() call for this iterator.
+  WrapFunc mWrapFunc;
   // Opaque data of the backing object.
-  IteratorData mData;
+  void* mData{nullptr};
 };
 
-namespace binding_detail {
-
-template <typename T>
-using IterableIteratorWrapFunc =
-    bool (*)(JSContext* aCx, IterableIterator<T>* aObject,
-             JS::MutableHandle<JSObject*> aReflector);
-
-template <typename T, IterableIteratorWrapFunc<T> WrapFunc>
-class WrappableIterableIterator final : public IterableIterator<T> {
- public:
-  using IterableIterator<T>::IterableIterator;
-
-  bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
-                  JS::MutableHandle<JSObject*> aObj) {
-    MOZ_ASSERT(!aGivenProto);
-    return (*WrapFunc)(aCx, this, aObj);
-  }
-};
-
-class AsyncIterableNextImpl {
- protected:
-  already_AddRefed<Promise> Next(JSContext* aCx,
-                                 AsyncIterableIteratorBase* aObject,
-                                 nsISupports* aGlobalObject, ErrorResult& aRv);
-  virtual already_AddRefed<Promise> GetNextResult(ErrorResult& aRv) = 0;
-
- private:
-  already_AddRefed<Promise> NextSteps(JSContext* aCx,
-                                      AsyncIterableIteratorBase* aObject,
-                                      nsIGlobalObject* aGlobalObject,
-                                      ErrorResult& aRv);
-};
-
-class AsyncIterableReturnImpl {
- protected:
-  already_AddRefed<Promise> Return(JSContext* aCx,
-                                   AsyncIterableIteratorBase* aObject,
-                                   nsISupports* aGlobalObject,
-                                   JS::Handle<JS::Value> aValue,
-                                   ErrorResult& aRv);
-  virtual already_AddRefed<Promise> GetReturnPromise(
-      JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) = 0;
-
- private:
-  already_AddRefed<Promise> ReturnSteps(JSContext* aCx,
-                                        AsyncIterableIteratorBase* aObject,
-                                        nsIGlobalObject* aGlobalObject,
-                                        JS::Handle<JS::Value> aValue,
-                                        ErrorResult& aRv);
-};
-
-template <typename T>
-class AsyncIterableIteratorNoReturn : public AsyncIterableIterator<T>,
-                                      public AsyncIterableNextImpl {
- public:
-  using AsyncIterableIterator<T>::AsyncIterableIterator;
-
-  already_AddRefed<Promise> Next(JSContext* aCx, ErrorResult& aRv) {
-    return AsyncIterableNextImpl::Next(
-        aCx, this, this->mIterableObj->GetParentObject(), aRv);
-  }
-
- protected:
-  already_AddRefed<Promise> GetNextResult(ErrorResult& aRv) override {
-    return this->mIterableObj->GetNextIterationResult(
-        static_cast<AsyncIterableIterator<T>*>(this), aRv);
-  }
-};
-
-template <typename T>
-class AsyncIterableIteratorWithReturn : public AsyncIterableIteratorNoReturn<T>,
-                                        public AsyncIterableReturnImpl {
- public:
-  already_AddRefed<Promise> Return(JSContext* aCx, JS::Handle<JS::Value> aValue,
-                                   ErrorResult& aRv) {
-    return AsyncIterableReturnImpl::Return(
-        aCx, this, this->mIterableObj->GetParentObject(), aValue, aRv);
-  }
-
- protected:
-  using AsyncIterableIteratorNoReturn<T>::AsyncIterableIteratorNoReturn;
-
-  already_AddRefed<Promise> GetReturnPromise(JSContext* aCx,
-                                             JS::Handle<JS::Value> aValue,
-                                             ErrorResult& aRv) override {
-    return this->mIterableObj->IteratorReturn(
-        aCx, static_cast<AsyncIterableIterator<T>*>(this), aValue, aRv);
-  }
-};
-
-template <typename T, bool NeedReturnMethod>
-using AsyncIterableIteratorNative =
-    std::conditional_t<NeedReturnMethod, AsyncIterableIteratorWithReturn<T>,
-                       AsyncIterableIteratorNoReturn<T>>;
-
-template <typename T, bool NeedReturnMethod>
-using AsyncIterableIteratorWrapFunc = bool (*)(
-    JSContext* aCx, AsyncIterableIteratorNative<T, NeedReturnMethod>* aObject,
-    JS::MutableHandle<JSObject*> aReflector);
-
-template <typename T, bool NeedReturnMethod,
-          AsyncIterableIteratorWrapFunc<T, NeedReturnMethod> WrapFunc,
-          typename Base = AsyncIterableIteratorNative<T, NeedReturnMethod>>
-class WrappableAsyncIterableIterator final : public Base {
- public:
-  using Base::Base;
-
-  bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
-                  JS::MutableHandle<JSObject*> aObj) {
-    MOZ_ASSERT(!aGivenProto);
-    return (*WrapFunc)(aCx, this, aObj);
-  }
-};
-
-}  // namespace binding_detail
-
 }  // namespace mozilla::dom
 
 #endif  // mozilla_dom_IterableIterator_h
diff --git a/dom/bindings/ToJSValue.h b/dom/bindings/ToJSValue.h
index 4655993578b9d..2117305173999 100644
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -406,34 +406,6 @@ template <typename T>
   return true;
 }
 
-// Accept tuple of other things we accept. The result will be a JS array object.
-template <typename... Elements>
-[[nodiscard]] bool ToJSValue(JSContext* aCx,
-                             const Tuple<Elements...>& aArguments,
-                             JS::MutableHandle<JS::Value> aValue) {
-  // Make sure we're called in a compartment
-  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
-
-  JS::RootedVector<JS::Value> v(aCx);
-  if (!v.resize(sizeof...(Elements))) {
-    return false;
-  }
-  bool ok = true;
-  size_t i = 0;
-  ForEach(aArguments, [aCx, &ok, &v, &i](auto& aElem) {
-    ok = ok && ToJSValue(aCx, aElem, v[i++]);
-  });
-  if (!ok) {
-    return false;
-  }
-  JSObject* arrayObj = JS::NewArrayObject(aCx, v);
-  if (!arrayObj) {
-    return false;
-  }
-  aValue.setObject(*arrayObj);
-  return true;
-}
-
 // Accept records of other things we accept. N.B. This assumes that
 // keys are either UTF-8 or UTF-16-ish. See Bug 1706058.
 template <typename K, typename V>
diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py
index ddfce6488bf10..c6581ef2249c6 100644
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -8886,6 +8886,7 @@ class Parser(Tokenizer):
             if isinstance(p, IDLInterface):
                 interfaceStatements.append(p)
 
+        iterableIteratorIface = None
         for iface in interfaceStatements:
             iterable = None
             # We haven't run finish() on the interface yet, so we don't know
@@ -8901,46 +8902,13 @@ class Parser(Tokenizer):
                 def simpleExtendedAttr(str):
                     return IDLExtendedAttribute(iface.location, (str,))
 
-                if isinstance(iterable, IDLAsyncIterable):
-                    nextReturnType = IDLPromiseType(
-                        iterable.location, BuiltinTypes[IDLBuiltinType.Types.any]
-                    )
-                else:
-                    nextReturnType = BuiltinTypes[IDLBuiltinType.Types.object]
                 nextMethod = IDLMethod(
-                    iterable.location,
-                    IDLUnresolvedIdentifier(iterable.location, "next"),
-                    nextReturnType,
+                    iface.location,
+                    IDLUnresolvedIdentifier(iface.location, "next"),
+                    BuiltinTypes[IDLBuiltinType.Types.object],
                     [],
                 )
                 nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
-
-                methods = [nextMethod]
-
-                if iterable.getExtendedAttribute("GenerateReturnMethod"):
-                    assert isinstance(iterable, IDLAsyncIterable)
-
-                    returnMethod = IDLMethod(
-                        iterable.location,
-                        IDLUnresolvedIdentifier(iterable.location, "return"),
-                        IDLPromiseType(
-                            iterable.location, BuiltinTypes[IDLBuiltinType.Types.any]
-                        ),
-                        [
-                            IDLArgument(
-                                iterable.location,
-                                IDLUnresolvedIdentifier(
-                                    BuiltinLocation("<auto-generated-identifier>"),
-                                    "value",
-                                ),
-                                BuiltinTypes[IDLBuiltinType.Types.any],
-                                optional=True,
-                            ),
-                        ],
-                    )
-                    returnMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
-                    methods.append(returnMethod)
-
                 if iterable.isIterable():
                     itr_suffix = "Iterator"
                 else:
@@ -8957,7 +8925,7 @@ class Parser(Tokenizer):
                     self.globalScope(),
                     itr_ident,
                     None,
-                    methods,
+                    [nextMethod],
                     isKnownNonPartial=True,
                     classNameOverride=classNameOverride,
                 )
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableDouble.cpp b/dom/bindings/test/TestInterfaceAsyncIterableDouble.cpp
index a0ec0d64f0914..c47bcb5aa299b 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableDouble.cpp
+++ b/dom/bindings/test/TestInterfaceAsyncIterableDouble.cpp
@@ -54,44 +54,73 @@ nsPIDOMWindowInner* TestInterfaceAsyncIterableDouble::GetParentObject() const {
   return mParent;
 }
 
-already_AddRefed<Promise>
-TestInterfaceAsyncIterableDouble::GetNextIterationResult(Iterator* aIterator,
-                                                         ErrorResult& aRv) {
+void TestInterfaceAsyncIterableDouble::InitAsyncIterator(Iterator* aIterator,
+                                                         ErrorResult& aError) {
+  UniquePtr<IteratorData> data(new IteratorData(0));
+  aIterator->SetData((void*)data.release());
+}
+
+void TestInterfaceAsyncIterableDouble::DestroyAsyncIterator(
+    Iterator* aIterator) {
+  auto* data = reinterpret_cast<IteratorData*>(aIterator->GetData());
+  delete data;
+}
+
+already_AddRefed<Promise> TestInterfaceAsyncIterableDouble::GetNextPromise(
+    JSContext* aCx, Iterator* aIterator, ErrorResult& aRv) {
   RefPtr<Promise> promise = Promise::Create(mParent->AsGlobal(), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  NS_DispatchToMainThread(NewRunnableMethod<RefPtr<Iterator>, RefPtr<Promise>>(
-      "TestInterfaceAsyncIterableDouble::GetNextIterationResult", this,
-      &TestInterfaceAsyncIterableDouble::ResolvePromise, aIterator, promise));
+  auto* data = reinterpret_cast<IteratorData*>(aIterator->GetData());
+  data->mPromise = promise;
+
+  IterableIteratorBase::IteratorType type = aIterator->GetIteratorType();
+  NS_DispatchToMainThread(NS_NewRunnableFunction(
+      "TestInterfaceAsyncIterableDouble::GetNextPromise",
+      [data, type, self = RefPtr{this}] { self->ResolvePromise(data, type); }));
 
   return promise.forget();
 }
 
-void TestInterfaceAsyncIterableDouble::ResolvePromise(Iterator* aIterator,
-                                                      Promise* aPromise) {
-  IteratorData& data = aIterator->Data();
+void TestInterfaceAsyncIterableDouble::ResolvePromise(
+    IteratorData* aData, IterableIteratorBase::IteratorType aType) {
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mParent))) {
+    return;
+  }
+  JSContext* cx = jsapi.cx();
+  ErrorResult rv;
 
   // Test data: ['a', 'b'], ['c', 'd'], ['e', 'f']
-  uint32_t idx = data.mIndex;
+  uint32_t idx = aData->mIndex;
   if (idx >= mValues.Length()) {
-    iterator_utils::ResolvePromiseForFinished(aPromise);
+    iterator_utils::ResolvePromiseForFinished(cx, aData->mPromise, rv);
   } else {
-    switch (aIterator->GetIteratorType()) {
+    JS::Rooted<JS::Value> key(cx);
+    JS::Rooted<JS::Value> value(cx);
+    switch (aType) {
       case IterableIteratorBase::IteratorType::Keys:
-        aPromise->MaybeResolve(mValues[idx].first);
+        Unused << ToJSValue(cx, mValues[idx].first, &key);
+        iterator_utils::ResolvePromiseWithKeyOrValue(cx, aData->mPromise, key,
+                                                     rv);
         break;
       case IterableIteratorBase::IteratorType::Values:
-        aPromise->MaybeResolve(mValues[idx].second);
+        Unused << ToJSValue(cx, mValues[idx].second, &value);
+        iterator_utils::ResolvePromiseWithKeyOrValue(cx, aData->mPromise, value,
+                                                     rv);
         break;
       case IterableIteratorBase::IteratorType::Entries:
-        iterator_utils::ResolvePromiseWithKeyAndValue(
-            aPromise, mValues[idx].first, mValues[idx].second);
+        Unused << ToJSValue(cx, mValues[idx].first, &key);
+        Unused << ToJSValue(cx, mValues[idx].second, &value);
+        iterator_utils::ResolvePromiseWithKeyAndValue(cx, aData->mPromise, key,
+                                                      value, rv);
         break;
     }
 
-    data.mIndex++;
+    aData->mIndex++;
+    aData->mPromise = nullptr;
   }
 }
 
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableDouble.h b/dom/bindings/test/TestInterfaceAsyncIterableDouble.h
index 4b458617dc677..cbf9e19ad621a 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableDouble.h
+++ b/dom/bindings/test/TestInterfaceAsyncIterableDouble.h
@@ -38,21 +38,27 @@ class TestInterfaceAsyncIterableDouble final : public nsISupports,
   static already_AddRefed<TestInterfaceAsyncIterableDouble> Constructor(
       const GlobalObject& aGlobal, ErrorResult& rv);
 
-  struct IteratorData {
-    uint32_t mIndex = 0;
-  };
-
   using Iterator = AsyncIterableIterator<TestInterfaceAsyncIterableDouble>;
-
-  void InitAsyncIteratorData(IteratorData& aData, Iterator::IteratorType aType,
-                             ErrorResult& aError) {}
-
-  already_AddRefed<Promise> GetNextIterationResult(Iterator* aIterator,
-                                                   ErrorResult& aRv);
+  void InitAsyncIterator(Iterator* aIterator, ErrorResult& aError);
+  void DestroyAsyncIterator(Iterator* aIterator);
+  already_AddRefed<Promise> GetNextPromise(JSContext* aCx, Iterator* aIterator,
+                                           ErrorResult& aRv);
 
  private:
+  struct IteratorData {
+    explicit IteratorData(int32_t aIndex) : mIndex(aIndex) {}
+    ~IteratorData() {
+      if (mPromise) {
+        mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+        mPromise = nullptr;
+      }
+    }
+    RefPtr<Promise> mPromise;
+    uint32_t mIndex;
+  };
   virtual ~TestInterfaceAsyncIterableDouble() = default;
-  void ResolvePromise(Iterator* aIterator, Promise* aPromise);
+  void ResolvePromise(IteratorData* aData,
+                      IterableIteratorBase::IteratorType aType);
 
   nsCOMPtr<nsPIDOMWindowInner> mParent;
   nsTArray<std::pair<nsString, nsString>> mValues;
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.cpp b/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.cpp
index 300574d7d70f0..c001aa7da56dd 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.cpp
+++ b/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.cpp
@@ -60,46 +60,74 @@ nsPIDOMWindowInner* TestInterfaceAsyncIterableDoubleUnion::GetParentObject()
   return mParent;
 }
 
-already_AddRefed<Promise>
-TestInterfaceAsyncIterableDoubleUnion::GetNextIterationResult(
-    Iterator* aIterator, ErrorResult& aRv) {
+void TestInterfaceAsyncIterableDoubleUnion::InitAsyncIterator(
+    Iterator* aIterator, ErrorResult& aError) {
+  UniquePtr<IteratorData> data(new IteratorData(0));
+  aIterator->SetData((void*)data.release());
+}
+
+void TestInterfaceAsyncIterableDoubleUnion::DestroyAsyncIterator(
+    Iterator* aIterator) {
+  auto* data = reinterpret_cast<IteratorData*>(aIterator->GetData());
+  delete data;
+}
+
+already_AddRefed<Promise> TestInterfaceAsyncIterableDoubleUnion::GetNextPromise(
+    JSContext* aCx, Iterator* aIterator, ErrorResult& aRv) {
   RefPtr<Promise> promise = Promise::Create(mParent->AsGlobal(), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  NS_DispatchToMainThread(NewRunnableMethod<RefPtr<Iterator>, RefPtr<Promise>>(
-      "TestInterfaceAsyncIterableDoubleUnion::GetNextIterationResult", this,
-      &TestInterfaceAsyncIterableDoubleUnion::ResolvePromise, aIterator,
-      promise));
+  auto* data = reinterpret_cast<IteratorData*>(aIterator->GetData());
+  data->mPromise = promise;
+
+  IterableIteratorBase::IteratorType type = aIterator->GetIteratorType();
+  NS_DispatchToMainThread(NS_NewRunnableFunction(
+      "TestInterfaceAsyncIterableDoubleUnion::GetNextPromise",
+      [data, type, self = RefPtr{this}] { self->ResolvePromise(data, type); }));
 
   return promise.forget();
 }
 
-void TestInterfaceAsyncIterableDoubleUnion::ResolvePromise(Iterator* aIterator,
-                                                           Promise* aPromise) {
-  IteratorData& data = aIterator->Data();
+void TestInterfaceAsyncIterableDoubleUnion::ResolvePromise(
+    IteratorData* aData, IterableIteratorBase::IteratorType aType) {
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mParent))) {
+    return;
+  }
+  JSContext* cx = jsapi.cx();
+  ErrorResult rv;
 
   // Test data:
   // [long, 1], [string, "a"]
-  uint32_t idx = data.mIndex;
+  uint32_t idx = aData->mIndex;
   if (idx >= mValues.Length()) {
-    iterator_utils::ResolvePromiseForFinished(aPromise);
+    iterator_utils::ResolvePromiseForFinished(cx, aData->mPromise, rv);
   } else {
-    switch (aIterator->GetIteratorType()) {
+    JS::Rooted<JS::Value> key(cx);
+    JS::Rooted<JS::Value> value(cx);
+    switch (aType) {
       case IterableIteratorBase::IteratorType::Keys:
-        aPromise->MaybeResolve(mValues[idx].first);
+        Unused << ToJSValue(cx, mValues[idx].first, &key);
+        iterator_utils::ResolvePromiseWithKeyOrValue(cx, aData->mPromise, key,
+                                                     rv);
         break;
       case IterableIteratorBase::IteratorType::Values:
-        aPromise->MaybeResolve(mValues[idx].second);
+        Unused << ToJSValue(cx, mValues[idx].second, &value);
+        iterator_utils::ResolvePromiseWithKeyOrValue(cx, aData->mPromise, value,
+                                                     rv);
         break;
       case IterableIteratorBase::IteratorType::Entries:
-        iterator_utils::ResolvePromiseWithKeyAndValue(
-            aPromise, mValues[idx].first, mValues[idx].second);
+        Unused << ToJSValue(cx, mValues[idx].first, &key);
+        Unused << ToJSValue(cx, mValues[idx].second, &value);
+        iterator_utils::ResolvePromiseWithKeyAndValue(cx, aData->mPromise, key,
+                                                      value, rv);
         break;
     }
 
-    data.mIndex++;
+    aData->mIndex++;
+    aData->mPromise = nullptr;
   }
 }
 
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.h b/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.h
index 902c99b1a91e6..d3e34f3ece0a4 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.h
+++ b/dom/bindings/test/TestInterfaceAsyncIterableDoubleUnion.h
@@ -38,21 +38,28 @@ class TestInterfaceAsyncIterableDoubleUnion final : public nsISupports,
   static already_AddRefed<TestInterfaceAsyncIterableDoubleUnion> Constructor(
       const GlobalObject& aGlobal, ErrorResult& rv);
 
-  struct IteratorData {
-    uint32_t mIndex = 0;
-  };
-
   using Iterator = AsyncIterableIterator<TestInterfaceAsyncIterableDoubleUnion>;
-
-  void InitAsyncIteratorData(IteratorData& aData, Iterator::IteratorType aType,
-                             ErrorResult& aError) {}
-
-  already_AddRefed<Promise> GetNextIterationResult(Iterator* aIterator,
-                                                   ErrorResult& aRv);
+  void InitAsyncIterator(Iterator* aIterator, ErrorResult& aError);
+  void DestroyAsyncIterator(Iterator* aIterator);
+  already_AddRefed<Promise> GetNextPromise(JSContext* aCx, Iterator* aIterator,
+                                           ErrorResult& aRv);
 
  private:
+  struct IteratorData {
+    explicit IteratorData(int32_t aIndex) : mIndex(aIndex) {}
+    ~IteratorData() {
+      if (mPromise) {
+        mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+        mPromise = nullptr;
+      }
+    }
+    RefPtr<Promise> mPromise;
+    uint32_t mIndex;
+  };
+
   virtual ~TestInterfaceAsyncIterableDoubleUnion() = default;
-  void ResolvePromise(Iterator* aIterator, Promise* aPromise);
+  void ResolvePromise(IteratorData* aData,
+                      IterableIteratorBase::IteratorType aType);
 
   nsCOMPtr<nsPIDOMWindowInner> mParent;
   nsTArray<std::pair<nsString, OwningStringOrLong>> mValues;
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp b/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp
index 5c77ef868250f..2baa9286da446 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp
+++ b/dom/bindings/test/TestInterfaceAsyncIterableSingle.cpp
@@ -9,8 +9,6 @@
 #include "nsPIDOMWindow.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/IterableIterator.h"
-#include "mozilla/dom/Promise-inl.h"
-#include "nsThreadUtils.h"
 
 namespace mozilla::dom {
 
@@ -54,75 +52,68 @@ nsPIDOMWindowInner* TestInterfaceAsyncIterableSingle::GetParentObject() const {
   return mParent;
 }
 
-void TestInterfaceAsyncIterableSingle::InitAsyncIteratorData(
-    IteratorData& aData, Iterator::IteratorType aType, ErrorResult& aError) {
+void TestInterfaceAsyncIterableSingle::InitAsyncIterator(Iterator* aIterator,
+                                                         ErrorResult& aError) {
   if (mFailToInit) {
     aError.ThrowTypeError("Caller asked us to fail");
     return;
   }
 
-  // Nothing else to do.
-  MOZ_ASSERT(aData.mIndex == 0);
-  MOZ_ASSERT(aData.mMultiplier == 1);
+  UniquePtr<IteratorData> data(new IteratorData(0, 1));
+  aIterator->SetData((void*)data.release());
 }
 
-already_AddRefed<Promise>
-TestInterfaceAsyncIterableSingle::GetNextIterationResult(Iterator* aIterator,
-                                                         ErrorResult& aRv) {
-  return GetNextIterationResult(aIterator, aIterator->Data(), aRv);
+void TestInterfaceAsyncIterableSingle::DestroyAsyncIterator(
+    Iterator* aIterator) {
+  auto* data = reinterpret_cast<IteratorData*>(aIterator->GetData());
+  delete data;
 }
 
-already_AddRefed<Promise>
-TestInterfaceAsyncIterableSingle::GetNextIterationResult(
-    IterableIteratorBase* aIterator, IteratorData& aData, ErrorResult& aRv) {
+already_AddRefed<Promise> TestInterfaceAsyncIterableSingle::GetNextPromise(
+    JSContext* aCx, Iterator* aIterator, ErrorResult& aRv) {
+  return GetNextPromise(aCx, aIterator,
+                        reinterpret_cast<IteratorData*>(aIterator->GetData()),
+                        aRv);
+}
+
+already_AddRefed<Promise> TestInterfaceAsyncIterableSingle::GetNextPromise(
+    JSContext* aCx, IterableIteratorBase* aIterator, IteratorData* aData,
+    ErrorResult& aRv) {
   RefPtr<Promise> promise = Promise::Create(mParent->AsGlobal(), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
+  aData->mPromise = promise;
 
-  nsCOMPtr<nsIRunnable> callResolvePromise =
-      NewRunnableMethod<RefPtr<IterableIteratorBase>, IteratorData&,
-                        RefPtr<Promise>>(
-          "TestInterfaceAsyncIterableSingle::GetNextIterationResult", this,
-          &TestInterfaceAsyncIterableSingle::ResolvePromise, aIterator, aData,
-          promise);
-  if (aData.mBlockingPromisesIndex < aData.mBlockingPromises.Length()) {
-    aData.mBlockingPromises[aData.mBlockingPromisesIndex]
-        ->AddCallbacksWithCycleCollectedArgs(
-            [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
-               nsIRunnable* aCallResolvePromise) {
-              NS_DispatchToMainThread(aCallResolvePromise);
-            },
-            [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
-               nsIRunnable* aCallResolvePromise) {},
-            std::move(callResolvePromise));
-    ++aData.mBlockingPromisesIndex;
-  } else {
-    NS_DispatchToMainThread(callResolvePromise);
-  }
+  NS_DispatchToMainThread(NS_NewRunnableFunction(
+      "TestInterfaceAsyncIterableSingle::GetNextPromise",
+      [iterator = RefPtr{aIterator}, aData, self = RefPtr{this}] {
+        self->ResolvePromise(iterator, aData);
+      }));
 
   return promise.forget();
 }
 
 void TestInterfaceAsyncIterableSingle::ResolvePromise(
-    IterableIteratorBase* aIterator, IteratorData& aData, Promise* aPromise) {
-  if (aData.mIndex >= 10) {
-    iterator_utils::ResolvePromiseForFinished(aPromise);
+    IterableIteratorBase* aIterator, IteratorData* aData) {
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mParent))) {
+    return;
+  }
+  JSContext* cx = jsapi.cx();
+  ErrorResult rv;
+  if (aData->mIndex >= 10) {
+    iterator_utils::ResolvePromiseForFinished(cx, aData->mPromise, rv);
   } else {
-    aPromise->MaybeResolve(int32_t(aData.mIndex * 9 % 7 * aData.mMultiplier));
+    JS::Rooted<JS::Value> value(cx);
+    Unused << ToJSValue(
+        cx, (int32_t)(aData->mIndex * 9 % 7 * aData->mMultiplier), &value);
+    iterator_utils::ResolvePromiseWithKeyOrValue(cx, aData->mPromise, value,
+                                                 rv);
 
-    aData.mIndex++;
+    aData->mIndex++;
   }
-}
-
-void TestInterfaceAsyncIterableSingle::IteratorData::Traverse(
-    nsCycleCollectionTraversalCallback& cb) {
-  TestInterfaceAsyncIterableSingle::IteratorData* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBlockingPromises);
-}
-void TestInterfaceAsyncIterableSingle::IteratorData::Unlink() {
-  TestInterfaceAsyncIterableSingle::IteratorData* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlockingPromises);
+  aData->mPromise = nullptr;
 }
 
 }  // namespace mozilla::dom
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingle.h b/dom/bindings/test/TestInterfaceAsyncIterableSingle.h
index a8da2336d6cad..9b8dbed67e20e 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableSingle.h
+++ b/dom/bindings/test/TestInterfaceAsyncIterableSingle.h
@@ -41,31 +41,35 @@ class TestInterfaceAsyncIterableSingle : public nsISupports,
       const TestInterfaceAsyncIterableSingleOptions& aOptions, ErrorResult& rv);
 
   using Iterator = AsyncIterableIterator<TestInterfaceAsyncIterableSingle>;
-  already_AddRefed<Promise> GetNextIterationResult(Iterator* aIterator,
-                                                   ErrorResult& aRv);
+  void InitAsyncIterator(Iterator* aIterator, ErrorResult& aError);
+  void DestroyAsyncIterator(Iterator* aIterator);
+  already_AddRefed<Promise> GetNextPromise(JSContext* aCx, Iterator* aIterator,
+                                           ErrorResult& aRv);
 
+ protected:
   struct IteratorData {
-    void Traverse(nsCycleCollectionTraversalCallback& cb);
-    void Unlink();
-
-    uint32_t mIndex = 0;
-    uint32_t mMultiplier = 1;
-    Sequence<OwningNonNull<Promise>> mBlockingPromises;
-    size_t mBlockingPromisesIndex = 0;
+    IteratorData(int32_t aIndex, uint32_t aMultiplier)
+        : mIndex(aIndex), mMultiplier(aMultiplier) {}
+    ~IteratorData() {
+      if (mPromise) {
+        mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+        mPromise = nullptr;
+      }
+    }
+    RefPtr<Promise> mPromise;
+    uint32_t mIndex;
+    uint32_t mMultiplier;
   };
 
-  void InitAsyncIteratorData(IteratorData& aData, Iterator::IteratorType aType,
-                             ErrorResult& aError);
-
- protected:
-  already_AddRefed<Promise> GetNextIterationResult(
-      IterableIteratorBase* aIterator, IteratorData& aData, ErrorResult& aRv);
+  already_AddRefed<Promise> GetNextPromise(JSContext* aCx,
+                                           IterableIteratorBase* aIterator,
+                                           IteratorData* aData,
+                                           ErrorResult& aRv);
 
   virtual ~TestInterfaceAsyncIterableSingle() = default;
 
  private:
-  void ResolvePromise(IterableIteratorBase* aIterator, IteratorData& aData,
-                      Promise* aPromise);
+  void ResolvePromise(IterableIteratorBase* aIterator, IteratorData* aData);
 
   nsCOMPtr<nsPIDOMWindowInner> mParent;
   bool mFailToInit;
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp
index 02e459fccf4cb..aa8f61b094fe6 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp
+++ b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.cpp
@@ -5,39 +5,13 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/TestInterfaceAsyncIterableSingleWithArgs.h"
-#include "js/Value.h"
 #include "mozilla/dom/TestInterfaceJSMaplikeSetlikeIterableBinding.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/IterableIterator.h"
-#include "mozilla/dom/Promise-inl.h"
 
 namespace mozilla::dom {
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(TestInterfaceAsyncIterableSingleWithArgs)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(
-    TestInterfaceAsyncIterableSingleWithArgs, TestInterfaceAsyncIterableSingle)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
-    TestInterfaceAsyncIterableSingleWithArgs, TestInterfaceAsyncIterableSingle)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(
-    TestInterfaceAsyncIterableSingleWithArgs, TestInterfaceAsyncIterableSingle)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReturnLastCalledWith)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_ADDREF_INHERITED(TestInterfaceAsyncIterableSingleWithArgs,
-                         TestInterfaceAsyncIterableSingle)
-NS_IMPL_RELEASE_INHERITED(TestInterfaceAsyncIterableSingleWithArgs,
-                          TestInterfaceAsyncIterableSingle)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
-    TestInterfaceAsyncIterableSingleWithArgs)
-NS_INTERFACE_MAP_END_INHERITING(TestInterfaceAsyncIterableSingle)
-
 // static
 already_AddRefed<TestInterfaceAsyncIterableSingleWithArgs>
 TestInterfaceAsyncIterableSingleWithArgs::Constructor(
@@ -60,34 +34,26 @@ JSObject* TestInterfaceAsyncIterableSingleWithArgs::WrapObject(
                                                                 aGivenProto);
 }
 
-void TestInterfaceAsyncIterableSingleWithArgs::InitAsyncIteratorData(
-    IteratorData& aData, Iterator::IteratorType aType,
-    const TestInterfaceAsyncIteratorOptions& aOptions, ErrorResult& aError) {
-  aData.mMultiplier = aOptions.mMultiplier;
-  aData.mBlockingPromises = aOptions.mBlockingPromises;
+void TestInterfaceAsyncIterableSingleWithArgs::InitAsyncIterator(
+    Iterator* aIterator, const TestInterfaceAsyncIteratorOptions& aOptions,
+    ErrorResult& aError) {
+  UniquePtr<IteratorData> data(new IteratorData(0, aOptions.mMultiplier));
+  aIterator->SetData((void*)data.release());
 }
 
-already_AddRefed<Promise>
-TestInterfaceAsyncIterableSingleWithArgs::GetNextIterationResult(
-    Iterator* aIterator, ErrorResult& aRv) {
-  return TestInterfaceAsyncIterableSingle::GetNextIterationResult(
-      aIterator, aIterator->Data(), aRv);
+void TestInterfaceAsyncIterableSingleWithArgs::DestroyAsyncIterator(
+    Iterator* aIterator) {
+  auto* data = reinterpret_cast<IteratorData*>(aIterator->GetData());
+  delete data;
 }
 
 already_AddRefed<Promise>
-TestInterfaceAsyncIterableSingleWithArgs::IteratorReturn(
-    JSContext* aCx, Iterator* aIterator, JS::Handle<JS::Value> aValue,
-    ErrorResult& aRv) {
-  ++mReturnCallCount;
-
-  RefPtr<Promise> promise = Promise::Create(GetParentObject()->AsGlobal(), aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  mReturnLastCalledWith = aValue;
-  promise->MaybeResolve(JS::UndefinedHandleValue);
-  return promise.forget();
+TestInterfaceAsyncIterableSingleWithArgs::GetNextPromise(JSContext* aCx,
+                                                         Iterator* aIterator,
+                                                         ErrorResult& aRv) {
+  return TestInterfaceAsyncIterableSingle::GetNextPromise(
+      aCx, aIterator, reinterpret_cast<IteratorData*>(aIterator->GetData()),
+      aRv);
 }
 
 }  // namespace mozilla::dom
diff --git a/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h
index a632f8b6eee7b..30d7b8455b6ca 100644
--- a/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h
+++ b/dom/bindings/test/TestInterfaceAsyncIterableSingleWithArgs.h
@@ -18,11 +18,6 @@ struct TestInterfaceAsyncIteratorOptions;
 class TestInterfaceAsyncIterableSingleWithArgs final
     : public TestInterfaceAsyncIterableSingle {
  public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
-      TestInterfaceAsyncIterableSingleWithArgs,
-      TestInterfaceAsyncIterableSingle)
-
   using TestInterfaceAsyncIterableSingle::TestInterfaceAsyncIterableSingle;
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
@@ -31,28 +26,13 @@ class TestInterfaceAsyncIterableSingleWithArgs final
 
   using Iterator =
       AsyncIterableIterator<TestInterfaceAsyncIterableSingleWithArgs>;
+  void InitAsyncIterator(Iterator* aIterator,
+                         const TestInterfaceAsyncIteratorOptions& aOptions,
+                         ErrorResult& aError);
+  void DestroyAsyncIterator(Iterator* aIterator);
 
-  void InitAsyncIteratorData(IteratorData& aData, Iterator::IteratorType aType,
-                             const TestInterfaceAsyncIteratorOptions& aOptions,
-                             ErrorResult& aError);
-
-  already_AddRefed<Promise> GetNextIterationResult(Iterator* aIterator,
-                                                   ErrorResult& aRv);
-  already_AddRefed<Promise> IteratorReturn(JSContext* aCx, Iterator* aIterator,
-                                           JS::Handle<JS::Value> aValue,
+  already_AddRefed<Promise> GetNextPromise(JSContext* aCx, Iterator* aIterator,
                                            ErrorResult& aRv);
-
-  uint32_t ReturnCallCount() { return mReturnCallCount; }
-  void GetReturnLastCalledWith(JSContext* aCx,
-                               JS::MutableHandle<JS::Value> aReturnCalledWith) {
-    aReturnCalledWith.set(mReturnLastCalledWith);
-  }
-
- private:
-  ~TestInterfaceAsyncIterableSingleWithArgs() = default;
-
-  JS::Heap<JS::Value> mReturnLastCalledWith;
-  uint32_t mReturnCallCount = 0;
 };
 
 }  // namespace mozilla::dom
diff --git a/dom/bindings/test/test_async_iterable.html b/dom/bindings/test/test_async_iterable.html
index 8dabf157d8e1c..03af2097a5e72 100644
--- a/dom/bindings/test/test_async_iterable.html
+++ b/dom/bindings/test/test_async_iterable.html
@@ -14,24 +14,17 @@ add_task(async function init() {
   await SpecialPowers.pushPrefEnv({set: [["dom.expose_test_interfaces", true]]});
 });
 
-const singleValues = Array(10).fill(0).map((_, i) => i * 9 % 7);
-
-async function check_single_result_values(values, multiplier = 1) {
-  dump(JSON.stringify(values));
-  is(values.length, 10, `AsyncIterableSingle: should return 10 elements`);
-  for (let i = 0; i < 10; i++) {
-    let expected = singleValues[i] * multiplier;
-    is(values[i], expected,
-      `AsyncIterableSingle: should be ${expected}, get ${values[i]}`);
-  }
-}
-
 async function check_single_result(itr, multiplier = 1) {
   let values = [];
   for await (let v of itr) {
     values.push(v);
   }
-  check_single_result_values(values, multiplier);
+  is(values.length, 10, `AsyncIterableSingle: should returns 10 elements`);
+  for (let i = 0; i < 10; i++) {
+    let expected = i * 9 % 7 * multiplier;
+    is(values[i], expected,
+      `AsyncIterableSingle: should be ${expected}, get ${values[i]}`);
+  }
 }
 
 async function test_data_single() {
@@ -65,104 +58,6 @@ async function test_data_single() {
 
   await check_single_result(itr, 1);
   await check_single_result(itr.values({ multiplier: 2 }), 2);
-
-  // eslint-disable-next-line no-undef
-  itr = new TestInterfaceAsyncIterableSingle();
-  let itrValues = itr.values();
-  let values = [];
-  for (let i = 0; i < 10; ++i) {
-    values.push(itrValues.next());
-  }
-  check_single_result_values(await Promise.all(values).then(v => v.map(w => w.value)));
-
-  // Test that there is only one ongoing promise at a time.
-  // Async iterables return a promise that is then resolved with the iterator
-  // value. We create an array of unresolved promises here, one promise for
-  // every result that we expect from the iterator. We pass that array of
-  // promises to the .value() method of the
-  // TestInterfaceAsyncIterableSingleWithArgs, and it will chain the resolving
-  // of each resulting iterator value on the corresponding promise from this
-  // array. We then resolve the promises in the array one by one in reverse
-  // order. This tries to make sure that the iterator always resolves the
-  // promises in the order of iteration.
-  let unblockers = [];
-  let blockingPromises = [];
-  for (let i = 0; i < 10; ++i) {
-    let unblocker;
-    let promise = new Promise((resolve, reject) => {
-      unblocker = resolve;
-    });
-    unblockers.push(unblocker);
-    blockingPromises.push(promise);
-  }
-
-  // eslint-disable-next-line no-undef
-  itr = new TestInterfaceAsyncIterableSingleWithArgs();
-  itrValues = itr.values({ blockingPromises });
-  values = [];
-  for (let i = 0; i < 10; ++i) {
-    values.push(itrValues.next());
-  }
-  unblockers.reverse();
-  for (let unblocker of unblockers) {
-    unblocker();
-  }
-
-  check_single_result_values(await Promise.all(values).then(v => v.map(w => w.value)));
-
-  // eslint-disable-next-line no-undef
-  itr = new TestInterfaceAsyncIterableSingleWithArgs();
-
-  let callCount = itr.returnCallCount;
-
-  let i = 0;
-  for await (let v of itr) {
-    if (++i > 1) {
-      break;
-    }
-    values.push(v);
-  }
-
-  is(itr.returnCallCount, callCount + 1,
-     `AsyncIterableSingle: breaking out of for-await-of loop should call "return"`);
-  is(itr.returnLastCalledWith, undefined,
-     `AsyncIterableSingleWithArgs: the asynchronous iterator return algorithm should be called with the argument that was passed in.`);
-
-  // eslint-disable-next-line no-undef
-  itr = new TestInterfaceAsyncIterableSingleWithArgs();
-
-  async function * yieldFromIterator () {
-    yield * itr
-  }
-
-  let yieldingIterator = yieldFromIterator();
-
-  let result = await yieldingIterator.next();
-  is(result.value, singleValues[0],
-     `AsyncIterableSingle: should be ${singleValues[0]}, get ${result.value}`);
-  result = await yieldingIterator.next();
-  is(result.value, singleValues[1],
-     `AsyncIterableSingle: should be ${singleValues[1]}, get ${result.value}`);
-
-  result = await yieldingIterator.return("abcd");
-  is(typeof result, "object",
-     `AsyncIterableSingleWithArgs: "return("abcd")" should return { done: true, value: "abcd" }`);
-  is(result.done, true,
-     `AsyncIterableSingleWithArgs: "return("abcd")" should return { done: true, value: "abcd" }`);
-  is(result.value, "abcd",
-     `AsyncIterableSingleWithArgs: "return("abcd")" should return { done: true, value: "abcd" }`);
-  is(itr.returnLastCalledWith, "abcd",
-     `AsyncIterableSingleWithArgs: the asynchronous iterator return algorithm should be called with the argument that was passed in.`);
-
-  result = await yieldingIterator.return("efgh");
-  is(typeof result, "object",
-     `AsyncIterableSingleWithArgs: "return("efgh")" should return { done: true, value: "efgh" }`);
-  is(result.done, true,
-     `AsyncIterableSingleWithArgs: "return("efgh")" should return { done: true, value: "efgh" }`);
-  is(result.value, "efgh",
-     `AsyncIterableSingleWithArgs: "return("efgh")" should return { done: true, value: "efgh" }`);
-  is(itr.returnLastCalledWith, "abcd",
-     `AsyncIterableSingleWithArgs: the asynchronous iterator return algorithm shouldn't be called if the iterator's 'is finished' flag is true already.`);
 }
 
 async function test_data_double() {
diff --git a/dom/broadcastchannel/BroadcastChannel.cpp b/dom/broadcastchannel/BroadcastChannel.cpp
index ee8581f769741..c3607e90a8a27 100644
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -14,7 +14,6 @@
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/dom/RefMessageBodyService.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/SharedMessageBody.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/WorkerRef.h"
diff --git a/dom/cache/Cache.cpp b/dom/cache/Cache.cpp
index d9b94f6b14bc7..5da7a5cb42a9b 100644
--- a/dom/cache/Cache.cpp
+++ b/dom/cache/Cache.cpp
@@ -13,7 +13,6 @@
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Response.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/CacheBinding.h"
 #include "mozilla/dom/cache/AutoUtils.h"
diff --git a/dom/cache/CacheStorage.h b/dom/cache/CacheStorage.h
index 306c7cccd42d2..78cbafe37e27e 100644
--- a/dom/cache/CacheStorage.h
+++ b/dom/cache/CacheStorage.h
@@ -20,8 +20,6 @@ class nsIGlobalObject;
 namespace mozilla {
 
 class ErrorResult;
-enum UseCounter : int16_t;
-enum class UseCounterWorker : int16_t;
 
 namespace ipc {
 class PrincipalInfo;
diff --git a/dom/cache/TypeUtils.cpp b/dom/cache/TypeUtils.cpp
index 07fe4223f4b68..029446ad18e72 100644
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -15,7 +15,6 @@
 #include "mozilla/dom/InternalRequest.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/ReadStream.h"
 #include "mozilla/ipc/BackgroundChild.h"
diff --git a/dom/fs/api/FileSystemDirectoryHandle.cpp b/dom/fs/api/FileSystemDirectoryHandle.cpp
index a2d4bfaad86e3..81fb530f5f208 100644
--- a/dom/fs/api/FileSystemDirectoryHandle.cpp
+++ b/dom/fs/api/FileSystemDirectoryHandle.cpp
@@ -12,6 +12,7 @@
 #include "js/TypeDecls.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/FileSystemDirectoryHandleBinding.h"
+#include "mozilla/dom/FileSystemDirectoryIterator.h"
 #include "mozilla/dom/FileSystemHandleBinding.h"
 #include "mozilla/dom/FileSystemManager.h"
 #include "mozilla/dom/PFileSystemManager.h"
@@ -50,15 +51,27 @@ FileSystemHandleKind FileSystemDirectoryHandle::Kind() const {
   return FileSystemHandleKind::Directory;
 }
 
-void FileSystemDirectoryHandle::InitAsyncIteratorData(
-    IteratorData& aData, iterator_t::IteratorType aType, ErrorResult& aError) {
-  aData.mImpl =
-      fs::FileSystemDirectoryIteratorFactory::Create(mMetadata, aType);
+void FileSystemDirectoryHandle::InitAsyncIterator(
+    FileSystemDirectoryHandle::iterator_t* aIterator, ErrorResult& aError) {
+  aIterator->SetData(
+      static_cast<void*>(fs::FileSystemDirectoryIteratorFactory::Create(
+                             mMetadata, aIterator->GetIteratorType())
+                             .release()));
 }
 
-already_AddRefed<Promise> FileSystemDirectoryHandle::GetNextIterationResult(
-    FileSystemDirectoryHandle::iterator_t* aIterator, ErrorResult& aError) {
-  return aIterator->Data().mImpl->Next(mGlobal, mManager, aError);
+void FileSystemDirectoryHandle::DestroyAsyncIterator(
+    FileSystemDirectoryHandle::iterator_t* aIterator) {
+  auto* it =
+      static_cast<FileSystemDirectoryIterator::Impl*>(aIterator->GetData());
+  delete it;
+  aIterator->SetData(nullptr);
+}
+
+already_AddRefed<Promise> FileSystemDirectoryHandle::GetNextPromise(
+    JSContext* /* aCx */, FileSystemDirectoryHandle::iterator_t* aIterator,
+    ErrorResult& aError) {
+  return static_cast<FileSystemDirectoryIterator::Impl*>(aIterator->GetData())
+      ->Next(mGlobal, mManager, aError);
 }
 
 already_AddRefed<Promise> FileSystemDirectoryHandle::GetFileHandle(
diff --git a/dom/fs/api/FileSystemDirectoryHandle.h b/dom/fs/api/FileSystemDirectoryHandle.h
index 36ac7455c55be..87b0695fd3ce1 100644
--- a/dom/fs/api/FileSystemDirectoryHandle.h
+++ b/dom/fs/api/FileSystemDirectoryHandle.h
@@ -17,6 +17,7 @@ class ErrorResult;
 
 namespace dom {
 
+class FileSystemDirectoryIterator;
 struct FileSystemGetFileOptions;
 struct FileSystemGetDirectoryOptions;
 struct FileSystemRemoveOptions;
@@ -45,16 +46,13 @@ class FileSystemDirectoryHandle final : public FileSystemHandle {
   // WebIDL Interface
   FileSystemHandleKind Kind() const override;
 
-  struct IteratorData {
-    UniquePtr<FileSystemDirectoryIterator::Impl> mImpl;
-  };
+  void InitAsyncIterator(iterator_t* aIterator, ErrorResult& aError);
 
-  void InitAsyncIteratorData(IteratorData& aData,
-                             iterator_t::IteratorType aType,
-                             ErrorResult& aError);
+  void DestroyAsyncIterator(iterator_t* aIterator);
 
-  [[nodiscard]] already_AddRefed<Promise> GetNextIterationResult(
-      iterator_t* aIterator, ErrorResult& aError);
+  [[nodiscard]] already_AddRefed<Promise> GetNextPromise(JSContext* aCx,
+                                                         iterator_t* aIterator,
+                                                         ErrorResult& aError);
 
   already_AddRefed<Promise> GetFileHandle(
       const nsAString& aName, const FileSystemGetFileOptions& aOptions,
diff --git a/dom/fs/child/FileSystemDirectoryIteratorFactory.cpp b/dom/fs/child/FileSystemDirectoryIteratorFactory.cpp
index ce2c9ac062f82..573b47c3f836a 100644
--- a/dom/fs/child/FileSystemDirectoryIteratorFactory.cpp
+++ b/dom/fs/child/FileSystemDirectoryIteratorFactory.cpp
@@ -22,23 +22,52 @@ namespace mozilla::dom::fs {
 
 namespace {
 
+inline JSContext* GetContext(const RefPtr<Promise>& aPromise) {
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(aPromise->GetGlobalObject()))) {
+    return nullptr;
+  }
+  return jsapi.cx();
+}
+
 template <IterableIteratorBase::IteratorType Type>
 struct ValueResolver;
 
 template <>
 struct ValueResolver<IterableIteratorBase::Keys> {
-  void operator()(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
-                  const FileSystemEntryMetadata& aValue,
-                  const RefPtr<Promise>& aPromise) {
-    aPromise->MaybeResolve(aValue.entryName());
+  nsresult operator()(nsIGlobalObject* aGlobal,
+                      RefPtr<FileSystemManager>& aManager,
+                      const FileSystemEntryMetadata& aValue,
+                      const RefPtr<Promise>& aPromise, ErrorResult& aError) {
+    JSContext* cx = GetContext(aPromise);
+    if (!cx) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    JS::Rooted<JS::Value> key(cx);
+
+    if (!ToJSValue(cx, aValue.entryName(), &key)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+
+    iterator_utils::ResolvePromiseWithKeyOrValue(cx, aPromise.get(), key,
+                                                 aError);
+
+    return NS_OK;
   }
 };
 
 template <>
 struct ValueResolver<IterableIteratorBase::Values> {
-  void operator()(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
-                  const FileSystemEntryMetadata& aValue,
-                  const RefPtr<Promise>& aPromise) {
+  nsresult operator()(nsIGlobalObject* aGlobal,
+                      RefPtr<FileSystemManager>& aManager,
+                      const FileSystemEntryMetadata& aValue,
+                      const RefPtr<Promise>& aPromise, ErrorResult& aError) {
+    JSContext* cx = GetContext(aPromise);
+    if (!cx) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
     RefPtr<FileSystemHandle> handle;
 
     if (aValue.directory()) {
@@ -47,15 +76,34 @@ struct ValueResolver<IterableIteratorBase::Values> {
       handle = new FileSystemFileHandle(aGlobal, aManager, aValue);
     }
 
-    aPromise->MaybeResolve(std::move(handle));
+    JS::Rooted<JS::Value> value(cx);
+    if (!ToJSValue(cx, handle, &value)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+
+    iterator_utils::ResolvePromiseWithKeyOrValue(cx, aPromise.get(), value,
+                                                 aError);
+
+    return NS_OK;
   }
 };
 
 template <>
 struct ValueResolver<IterableIteratorBase::Entries> {
-  void operator()(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
-                  const FileSystemEntryMetadata& aValue,
-                  const RefPtr<Promise>& aPromise) {
+  nsresult operator()(nsIGlobalObject* aGlobal,
+                      RefPtr<FileSystemManager>& aManager,
+                      const FileSystemEntryMetadata& aValue,
+                      const RefPtr<Promise>& aPromise, ErrorResult& aError) {
+    JSContext* cx = GetContext(aPromise);
+    if (!cx) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    JS::Rooted<JS::Value> key(cx);
+    if (!ToJSValue(cx, aValue.entryName(), &key)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+
     RefPtr<FileSystemHandle> handle;
 
     if (aValue.directory()) {
@@ -64,8 +112,15 @@ struct ValueResolver<IterableIteratorBase::Entries> {
       handle = new FileSystemFileHandle(aGlobal, aManager, aValue);
     }
 
-    iterator_utils::ResolvePromiseWithKeyAndValue(aPromise, aValue.entryName(),
-                                                  handle);
+    JS::Rooted<JS::Value> value(cx);
+    if (!ToJSValue(cx, handle, &value)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+
+    iterator_utils::ResolvePromiseWithKeyAndValue(cx, aPromise.get(), key,
+                                                  value, aError);
+
+    return NS_OK;
   }
 };
 
@@ -88,16 +143,27 @@ class DoubleBufferQueueImpl
   // XXX This doesn't have to be public
   void ResolveValue(nsIGlobalObject* aGlobal,
                     RefPtr<FileSystemManager>& aManager,
-                    const Maybe<DataType>& aValue, RefPtr<Promise> aPromise) {
+                    const Maybe<DataType>& aValue, RefPtr<Promise> aPromise,
+                    ErrorResult& aError) {
     MOZ_ASSERT(aPromise);
     MOZ_ASSERT(aPromise.get());
 
+    AutoJSAPI jsapi;
+    if (NS_WARN_IF(!jsapi.Init(aPromise->GetGlobalObject()))) {
+      aPromise->MaybeReject(NS_ERROR_DOM_UNKNOWN_ERR);
+      aError = NS_ERROR_DOM_UNKNOWN_ERR;
+      return;
+    }
+
+    JSContext* aCx = jsapi.cx();
+    MOZ_ASSERT(aCx);
+
     if (!aValue) {
-      iterator_utils::ResolvePromiseForFinished(aPromise);
+      iterator_utils::ResolvePromiseForFinished(aCx, aPromise.get(), aError);
       return;
     }
 
-    ValueResolver{}(aGlobal, aManager, *aValue, aPromise);
+    ValueResolver{}(aGlobal, aManager, *aValue, aPromise, aError);
   }
 
   already_AddRefed<Promise> Next(nsIGlobalObject* aGlobal,
@@ -108,7 +174,7 @@ class DoubleBufferQueueImpl
       return nullptr;
     }
 
-    next(aGlobal, aManager, promise);
+    next(aGlobal, aManager, promise, aError);
 
     return promise.forget();
   }
@@ -117,7 +183,7 @@ class DoubleBufferQueueImpl
 
  protected:
   void next(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
-            RefPtr<Promise> aResult) {
+            RefPtr<Promise> aResult, ErrorResult& aError) {
     MOZ_ASSERT(aResult);
 
     Maybe<DataType> rawValue;
@@ -129,7 +195,7 @@ class DoubleBufferQueueImpl
       ErrorResult rv;
       RefPtr<Promise> promise = Promise::Create(aGlobal, rv);
       if (rv.Failed()) {
-        aResult->MaybeReject(std::move(rv));
+        aResult->MaybeReject(NS_ERROR_DOM_UNKNOWN_ERR);
         return;
       }
 
@@ -159,7 +225,7 @@ class DoubleBufferQueueImpl
             }
 
             IgnoredErrorResult rv;
-            ResolveValue(global, manager, value, aResult);
+            ResolveValue(global, manager, value, aResult, rv);
           },
           [](nsresult aRv) {});
       promise->AppendNativeHandler(listener);
@@ -173,7 +239,7 @@ class DoubleBufferQueueImpl
 
     nextInternal(rawValue);
 
-    ResolveValue(aGlobal, aManager, rawValue, aResult);
+    ResolveValue(aGlobal, aManager, rawValue, aResult, aError);
   }
 
   bool nextInternal(Maybe<DataType>& aNext) {
diff --git a/dom/fs/test/gtest/api/TestFileSystemDirectoryHandle.cpp b/dom/fs/test/gtest/api/TestFileSystemDirectoryHandle.cpp
index 647f289bbd24d..6da71747c9a0a 100644
--- a/dom/fs/test/gtest/api/TestFileSystemDirectoryHandle.cpp
+++ b/dom/fs/test/gtest/api/TestFileSystemDirectoryHandle.cpp
@@ -9,6 +9,7 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/dom/FileSystemDirectoryHandle.h"
 #include "mozilla/dom/FileSystemDirectoryHandleBinding.h"
+#include "mozilla/dom/FileSystemDirectoryIterator.h"
 #include "mozilla/dom/FileSystemHandle.h"
 #include "mozilla/dom/FileSystemHandleBinding.h"
 #include "mozilla/dom/FileSystemManager.h"
@@ -29,6 +30,12 @@ class TestFileSystemDirectoryHandle : public ::testing::Test {
     mManager = MakeAndAddRef<FileSystemManager>(mGlobal, nullptr);
   }
 
+  FileSystemDirectoryHandle::iterator_t::WrapFunc GetWrapFunc() const {
+    return [](JSContext*, AsyncIterableIterator<FileSystemDirectoryHandle>*,
+              JS::Handle<JSObject*>,
+              JS::MutableHandle<JSObject*>) -> bool { return true; };
+  }
+
   nsIGlobalObject* mGlobal = GetGlobal();
   const IterableIteratorBase::IteratorType mIteratorType =
       IterableIteratorBase::IteratorType::Keys;
@@ -45,7 +52,7 @@ TEST_F(TestFileSystemDirectoryHandle, constructDirectoryHandleRefPointer) {
   ASSERT_TRUE(dirHandle);
 }
 
-TEST_F(TestFileSystemDirectoryHandle, initIterator) {
+TEST_F(TestFileSystemDirectoryHandle, initAndDestroyIterator) {
   RefPtr<FileSystemDirectoryHandle> dirHandle =
       MakeAndAddRef<FileSystemDirectoryHandle>(mGlobal, mManager, mMetadata,
                                                mRequestHandler.release());
@@ -53,19 +60,28 @@ TEST_F(TestFileSystemDirectoryHandle, initIterator) {
   ASSERT_TRUE(dirHandle);
 
   RefPtr<FileSystemDirectoryHandle::iterator_t> iterator =
-      new FileSystemDirectoryHandle::iterator_t(dirHandle.get(), mIteratorType);
+      new FileSystemDirectoryHandle::iterator_t(dirHandle.get(), mIteratorType,
+                                                GetWrapFunc());
   IgnoredErrorResult rv;
-  dirHandle->InitAsyncIteratorData(iterator->Data(), mIteratorType, rv);
-  ASSERT_TRUE(iterator->Data().mImpl);
+  dirHandle->InitAsyncIterator(iterator, rv);
+  ASSERT_TRUE(iterator->GetData());
+
+  dirHandle->DestroyAsyncIterator(iterator);
+  ASSERT_EQ(nullptr, iterator->GetData());
 }
 
 class MockFileSystemDirectoryIteratorImpl final
     : public FileSystemDirectoryIterator::Impl {
  public:
+  NS_INLINE_DECL_REFCOUNTING(MockFileSystemDirectoryIteratorImpl)
+
   MOCK_METHOD(already_AddRefed<Promise>, Next,
               (nsIGlobalObject * aGlobal, RefPtr<FileSystemManager>& aManager,
                ErrorResult& aError),
               (override));
+
+ protected:
+  ~MockFileSystemDirectoryIteratorImpl() = default;
 };
 
 TEST_F(TestFileSystemDirectoryHandle, isNextPromiseReturned) {
@@ -75,20 +91,22 @@ TEST_F(TestFileSystemDirectoryHandle, isNextPromiseReturned) {
 
   ASSERT_TRUE(dirHandle);
 
-  auto mockIter = MakeUnique<MockFileSystemDirectoryIteratorImpl>();
+  auto* mockIter = new MockFileSystemDirectoryIteratorImpl();
   IgnoredErrorResult error;
   EXPECT_CALL(*mockIter, Next(_, _, _))
       .WillOnce(::testing::Return(Promise::Create(mGlobal, error)));
 
   RefPtr<FileSystemDirectoryHandle::iterator_t> iterator =
-      MakeAndAddRef<FileSystemDirectoryHandle::iterator_t>(dirHandle.get(),
-                                                           mIteratorType);
-  iterator->Data().mImpl = std::move(mockIter);
+      MakeAndAddRef<FileSystemDirectoryHandle::iterator_t>(
+          dirHandle.get(), mIteratorType, GetWrapFunc());
+  iterator->SetData(static_cast<void*>(mockIter));
 
   IgnoredErrorResult rv;
   RefPtr<Promise> promise =
-      dirHandle->GetNextIterationResult(iterator.get(), rv);
+      dirHandle->GetNextPromise(nullptr, iterator.get(), rv);
   ASSERT_TRUE(promise);
+
+  dirHandle->DestroyAsyncIterator(iterator.get());
 }
 
 TEST_F(TestFileSystemDirectoryHandle, isHandleKindDirectory) {
diff --git a/dom/ipc/SharedMap.cpp b/dom/ipc/SharedMap.cpp
index 70e12784e925f..6bd83d822d358 100644
--- a/dom/ipc/SharedMap.cpp
+++ b/dom/ipc/SharedMap.cpp
@@ -15,7 +15,6 @@
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentProcessMessageManager.h"
 #include "mozilla/dom/IPCBlobUtils.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/IOBuffers.h"
 #include "mozilla/ScriptPreloader.h"
diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp
index 24100656591b1..0717d4fb6f5dd 100644
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -27,7 +27,6 @@
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
 #include "mozilla/dom/ServiceWorkerUtils.h"
diff --git a/dom/promise/Promise-inl.h b/dom/promise/Promise-inl.h
index f472acbc166c7..b238db446c9f3 100644
--- a/dom/promise/Promise-inl.h
+++ b/dom/promise/Promise-inl.h
@@ -227,15 +227,13 @@ class NativeThenHandler<ResolveCallback, RejectCallback, std::tuple<Args...>,
 
 }  // anonymous namespace
 
-template <typename ResolveCallback, typename RejectCallback, typename... Args,
-          typename... JSArgs>
-Result<RefPtr<Promise>, nsresult>
-Promise::ThenCatchWithCycleCollectedArgsJSImpl(
+template <typename ResolveCallback, typename RejectCallback, typename... Args>
+Promise::ThenResult<ResolveCallback, Args...>
+Promise::ThenCatchWithCycleCollectedArgsImpl(
     Maybe<ResolveCallback>&& aOnResolve, Maybe<RejectCallback>&& aOnReject,
-    std::tuple<Args...>&& aArgs, std::tuple<JSArgs...>&& aJSArgs) {
-  using HandlerType =
-      NativeThenHandler<ResolveCallback, RejectCallback, std::tuple<Args...>,
-                        std::tuple<JSArgs...>>;
+    Args&&... aArgs) {
+  using HandlerType = NativeThenHandler<ResolveCallback, RejectCallback,
+                                        std::tuple<Args...>, std::tuple<>>;
 
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(GetParentObject(), rv);
@@ -243,11 +241,10 @@ Promise::ThenCatchWithCycleCollectedArgsJSImpl(
     return Err(rv.StealNSResult());
   }
 
-  auto* handler = new (fallible)
-      HandlerType(promise, std::forward<Maybe<ResolveCallback>>(aOnResolve),
-                  std::forward<Maybe<RejectCallback>>(aOnReject),
-                  std::forward<std::tuple<Args...>>(aArgs),
-                  std::forward<std::tuple<JSArgs...>>(aJSArgs));
+  auto* handler = new (fallible) HandlerType(
+      promise, std::forward<Maybe<ResolveCallback>>(aOnResolve),
+      std::forward<Maybe<RejectCallback>>(aOnReject),
+      std::make_tuple(std::forward<Args>(aArgs)...), std::make_tuple());
 
   if (!handler) {
     return Err(NS_ERROR_OUT_OF_MEMORY);
@@ -257,17 +254,6 @@ Promise::ThenCatchWithCycleCollectedArgsJSImpl(
   return std::move(promise);
 }
 
-template <typename ResolveCallback, typename RejectCallback, typename... Args>
-Promise::ThenResult<ResolveCallback, Args...>
-Promise::ThenCatchWithCycleCollectedArgsImpl(
-    Maybe<ResolveCallback>&& aOnResolve, Maybe<RejectCallback>&& aOnReject,
-    Args&&... aArgs) {
-  return ThenCatchWithCycleCollectedArgsJSImpl(
-      std::forward<Maybe<ResolveCallback>>(aOnResolve),
-      std::forward<Maybe<RejectCallback>>(aOnReject),
-      std::make_tuple(std::forward<Args>(aArgs)...), std::make_tuple());
-}
-
 template <typename ResolveCallback, typename RejectCallback, typename... Args>
 Promise::ThenResult<ResolveCallback, Args...>
 Promise::ThenCatchWithCycleCollectedArgs(ResolveCallback&& aOnResolve,
@@ -293,22 +279,28 @@ Promise::ThenResult<Callback, Args...> Promise::CatchWithCycleCollectedArgs(
                                              std::forward<Args>(aArgs)...);
 }
 
-template <typename ResolveCallback, typename RejectCallback, typename ArgsTuple,
-          typename JSArgsTuple>
-Result<RefPtr<Promise>, nsresult> Promise::ThenCatchWithCycleCollectedArgsJS(
-    ResolveCallback&& aOnResolve, RejectCallback&& aOnReject, ArgsTuple&& aArgs,
-    JSArgsTuple&& aJSArgs) {
-  return ThenCatchWithCycleCollectedArgsJSImpl(
-      Some(aOnResolve), Some(aOnReject), std::forward<ArgsTuple>(aArgs),
-      std::forward<JSArgsTuple>(aJSArgs));
-}
-
 template <typename Callback, typename ArgsTuple, typename JSArgsTuple>
 Result<RefPtr<Promise>, nsresult> Promise::ThenWithCycleCollectedArgsJS(
     Callback&& aOnResolve, ArgsTuple&& aArgs, JSArgsTuple&& aJSArgs) {
-  return ThenCatchWithCycleCollectedArgsJSImpl(
-      Some(aOnResolve), Maybe<Callback>(Nothing()),
+  using HandlerType =
+      NativeThenHandler<Callback, Callback, ArgsTuple, JSArgsTuple>;
+
+  ErrorResult rv;
+  RefPtr<Promise> promise = Promise::Create(GetParentObject(), rv);
+  if (rv.Failed()) {
+    return Err(rv.StealNSResult());
+  }
+
+  auto* handler = new (fallible) HandlerType(
+      promise, Some(aOnResolve), Maybe<Callback>(Nothing()),
       std::forward<ArgsTuple>(aArgs), std::forward<JSArgsTuple>(aJSArgs));
+
+  if (!handler) {
+    return Err(NS_ERROR_OUT_OF_MEMORY);
+  }
+
+  AppendNativeHandler(handler);
+  return std::move(promise);
 }
 
 template <typename ResolveCallback, typename RejectCallback, typename... Args>
diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h
index 2c5d3e0f05379..578a959c2ae60 100644
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -275,14 +275,9 @@ class Promise : public SupportsWeakPtr {
   ThenResult<Callback, Args...> CatchWithCycleCollectedArgs(
       Callback&& aOnReject, Args&&... aArgs);
 
-  // Same as Then[Catch]CycleCollectedArgs but the arguments are gathered into
-  // an `std::tuple` and there is an additional `std::tuple` for JS arguments
-  // after that.
-  template <typename ResolveCallback, typename RejectCallback,
-            typename ArgsTuple, typename JSArgsTuple>
-  Result<RefPtr<Promise>, nsresult> ThenCatchWithCycleCollectedArgsJS(
-      ResolveCallback&& aOnResolve, RejectCallback&& aOnReject,
-      ArgsTuple&& aArgs, JSArgsTuple&& aJSArgs);
+  // Same as ThenCycleCollectedArgs but the arguments are gathered into an
+  // `std::tuple` and there is an additional `std::tuple` for JS arguments after
+  // that.
   template <typename Callback, typename ArgsTuple, typename JSArgsTuple>
   Result<RefPtr<Promise>, nsresult> ThenWithCycleCollectedArgsJS(
       Callback&& aOnResolve, ArgsTuple&& aArgs, JSArgsTuple&& aJSArgs);
@@ -337,11 +332,6 @@ class Promise : public SupportsWeakPtr {
       nsIGlobalObject* aGlobal, ErrorResult& aRejectionError);
 
  protected:
-  template <typename ResolveCallback, typename RejectCallback, typename... Args,
-            typename... JSArgs>
-  Result<RefPtr<Promise>, nsresult> ThenCatchWithCycleCollectedArgsJSImpl(
-      Maybe<ResolveCallback>&& aOnResolve, Maybe<RejectCallback>&& aOnReject,
-      std::tuple<Args...>&& aArgs, std::tuple<JSArgs...>&& aJSArgs);
   template <typename ResolveCallback, typename RejectCallback, typename... Args>
   ThenResult<ResolveCallback, Args...> ThenCatchWithCycleCollectedArgsImpl(
       Maybe<ResolveCallback>&& aOnResolve, Maybe<RejectCallback>&& aOnReject,
diff --git a/dom/promise/gtest/ThenWithCycleCollectedArgsJS.cpp b/dom/promise/gtest/ThenWithCycleCollectedArgsJS.cpp
index 31b9fde3cac2c..b97de65d093ad 100644
--- a/dom/promise/gtest/ThenWithCycleCollectedArgsJS.cpp
+++ b/dom/promise/gtest/ThenWithCycleCollectedArgsJS.cpp
@@ -78,81 +78,3 @@ TEST(ThenWithCycleCollectedArgsJS, Mixed)
       std::make_tuple(global, promise),
       std::make_tuple(JS::UndefinedHandleValue, JS::HandleObject(obj)));
 }
-
-TEST(ThenCatchWithCycleCollectedArgsJS, Empty)
-{
-  nsCOMPtr<nsIGlobalObject> global =
-      xpc::NativeGlobal(xpc::PrivilegedJunkScope());
-
-  RefPtr<Promise> promise = Promise::Create(global, IgnoreErrors());
-  auto result = promise->ThenCatchWithCycleCollectedArgsJS(
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&) { return nullptr; },
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&) { return nullptr; },
-      std::make_tuple(), std::make_tuple());
-}
-
-TEST(ThenCatchWithCycleCollectedArgsJS, nsCOMPtr)
-{
-  nsCOMPtr<nsIGlobalObject> global =
-      xpc::NativeGlobal(xpc::PrivilegedJunkScope());
-
-  RefPtr<Promise> promise = Promise::Create(global, IgnoreErrors());
-  auto result = promise->ThenCatchWithCycleCollectedArgsJS(
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, nsIGlobalObject*) {
-        return nullptr;
-      },
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, nsIGlobalObject*) {
-        return nullptr;
-      },
-      std::make_tuple(global), std::make_tuple());
-}
-
-TEST(ThenCatchWithCycleCollectedArgsJS, RefPtr)
-{
-  nsCOMPtr<nsIGlobalObject> global =
-      xpc::NativeGlobal(xpc::PrivilegedJunkScope());
-
-  RefPtr<Promise> promise = Promise::Create(global, IgnoreErrors());
-  auto result = promise->ThenCatchWithCycleCollectedArgsJS(
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, Promise*) {
-        return nullptr;
-      },
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, Promise*) {
-        return nullptr;
-      },
-      std::make_tuple(promise), std::make_tuple());
-}
-
-TEST(ThenCatchWithCycleCollectedArgsJS, RefPtrAndJSHandle)
-{
-  nsCOMPtr<nsIGlobalObject> global =
-      xpc::NativeGlobal(xpc::PrivilegedJunkScope());
-
-  RefPtr<Promise> promise = Promise::Create(global, IgnoreErrors());
-  auto result = promise->ThenCatchWithCycleCollectedArgsJS(
-      [](JSContext*, JS::Handle<JS::Value> v, ErrorResult&, Promise*,
-         JS::Handle<JS::Value>) { return nullptr; },
-      [](JSContext*, JS::Handle<JS::Value> v, ErrorResult&, Promise*,
-         JS::Handle<JS::Value>) { return nullptr; },
-      std::make_tuple(promise), std::make_tuple(JS::UndefinedHandleValue));
-}
-
-TEST(ThenCatchWithCycleCollectedArgsJS, Mixed)
-{
-  AutoJSAPI jsapi;
-  MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
-  JSContext* cx = jsapi.cx();
-  nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(cx);
-  JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
-
-  RefPtr<Promise> promise = Promise::Create(global, IgnoreErrors());
-  auto result = promise->ThenCatchWithCycleCollectedArgsJS(
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, nsIGlobalObject*,
-         Promise*, JS::Handle<JS::Value>,
-         JS::Handle<JSObject*>) { return nullptr; },
-      [](JSContext*, JS::Handle<JS::Value>, ErrorResult&, nsIGlobalObject*,
-         Promise*, JS::Handle<JS::Value>,
-         JS::Handle<JSObject*>) { return nullptr; },
-      std::make_tuple(global, promise),
-      std::make_tuple(JS::UndefinedHandleValue, JS::HandleObject(obj)));
-}
diff --git a/dom/serviceworkers/ServiceWorkerContainer.cpp b/dom/serviceworkers/ServiceWorkerContainer.cpp
index 2ce6b60d5b3fb..eeb5862f7680c 100644
--- a/dom/serviceworkers/ServiceWorkerContainer.cpp
+++ b/dom/serviceworkers/ServiceWorkerContainer.cpp
@@ -32,7 +32,6 @@
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/Promise.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/ServiceWorker.h"
 #include "mozilla/dom/ServiceWorkerContainerBinding.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
diff --git a/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl b/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl
index 2363a8930b29a..3dadf84301b0c 100644
--- a/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl
+++ b/dom/webidl/TestInterfaceJSMaplikeSetlikeIterable.webidl
@@ -111,7 +111,6 @@ interface TestInterfaceAsyncIterableSingle {
 
 dictionary TestInterfaceAsyncIteratorOptions {
   unsigned long multiplier = 1;
-  sequence<Promise<any>> blockingPromises = [];
 };
 
 [Pref="dom.expose_test_interfaces",
@@ -120,12 +119,7 @@ interface TestInterfaceAsyncIterableSingleWithArgs {
   [Throws]
   constructor();
 
-  [GenerateReturnMethod]
   async iterable<long>(optional TestInterfaceAsyncIteratorOptions options = {});
-
-  readonly attribute long returnCallCount;
-
-  readonly attribute any returnLastCalledWith;
 };
 
 [Pref="dom.expose_test_interfaces",
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index e15afcdebdecb..7ae860d4361ea 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -49,7 +49,6 @@
 #include "mozilla/dom/PromiseDebugging.h"
 #include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/RemoteWorkerService.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/WorkerScope.h"
diff --git a/dom/worklet/Worklet.cpp b/dom/worklet/Worklet.cpp
index a73be7c4f4155..36c4c66423d7c 100644
--- a/dom/worklet/Worklet.cpp
+++ b/dom/worklet/Worklet.cpp
@@ -16,7 +16,6 @@
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/dom/WorkletImpl.h"
diff --git a/mfbt/Tuple.h b/mfbt/Tuple.h
index 7fec059ef9679..85ff3f314e15d 100644
--- a/mfbt/Tuple.h
+++ b/mfbt/Tuple.h
@@ -116,7 +116,7 @@ struct TupleImpl<Index> {
   bool operator==(const TupleImpl<Index>& aOther) const { return true; }
 
   template <typename F>
-  void ForEach(const F& aFunc) const {}
+  void ForEach(const F& aFunc) {}
 };
 
 /*
@@ -449,7 +449,7 @@ inline void ForEach(Tuple<>& aTuple, const F& aFunc) {}
 
 template <typename F, typename... Elements>
 void ForEach(const Tuple<Elements...>& aTuple, const F& aFunc) {
-  aTuple.ForEach(aFunc);
+  aTuple.ForEach(aTuple, aFunc);
 }
 
 template <typename F, typename... Elements>
diff --git a/mfbt/tests/TestTuple.cpp b/mfbt/tests/TestTuple.cpp
index 4e20101972b4a..13f61048f1e0e 100644
--- a/mfbt/tests/TestTuple.cpp
+++ b/mfbt/tests/TestTuple.cpp
@@ -292,59 +292,6 @@ static bool TestTieIgnore() {
   return true;
 }
 
-template <typename... Elements, typename F>
-static void CheckForEachCall(const Tuple<Elements...>& aTuple,
-                             F&& CallForEach) {
-  constexpr std::size_t tupleSize = sizeof...(Elements);
-
-  Tuple<Elements...> checkResult;
-  std::size_t i = 0;
-  auto createResult = [&](auto& aElem) {
-    static_assert(tupleSize == 3,
-                  "Need to deal with more/less cases in the switch below");
-
-    CHECK(i < tupleSize);
-    switch (i) {
-      case 0:
-        Get<0>(checkResult) = aElem;
-        break;
-      case 1:
-        Get<1>(checkResult) = aElem;
-        break;
-      case 2:
-        Get<2>(checkResult) = aElem;
-        break;
-    }
-    ++i;
-  };
-
-  CallForEach(aTuple, createResult);
-
-  CHECK(checkResult == aTuple);
-}
-
-static bool TestForEach() {
-  Tuple<int, float, char> tuple = MakeTuple(42, 0.5f, 'c');
-
-  CheckForEachCall(
-      tuple, [](auto& aTuple, auto&& aLambda) { aTuple.ForEach(aLambda); });
-
-  CheckForEachCall(
-      tuple, [](auto& aTuple, auto&& aLambda) { ForEach(aTuple, aLambda); });
-
-  CheckForEachCall(tuple, [](auto& aTuple, auto&& aLambda) {
-    const decltype(aTuple)& constTuple = aTuple;
-    constTuple.ForEach(aLambda);
-  });
-
-  CheckForEachCall(tuple, [](auto& aTuple, auto&& aLambda) {
-    const decltype(aTuple)& constTuple = aTuple;
-    ForEach(constTuple, aLambda);
-  });
-
-  return true;
-}
-
 int main() {
   TestConstruction();
   TestConstructionFromMozPair();
@@ -357,6 +304,5 @@ int main() {
   TestTie();
   TestTieIgnore();
   TestTieMozPair();
-  TestForEach();
   return 0;
 }
diff --git a/toolkit/components/extensions/webrequest/StreamFilter.cpp b/toolkit/components/extensions/webrequest/StreamFilter.cpp
index aab284dda2028..c6d8361573de6 100644
--- a/toolkit/components/extensions/webrequest/StreamFilter.cpp
+++ b/toolkit/components/extensions/webrequest/StreamFilter.cpp
@@ -16,7 +16,6 @@
 #include "mozilla/extensions/StreamFilterParent.h"
 #include "mozilla/dom/AutoEntryScript.h"
 #include "mozilla/dom/ContentChild.h"
-#include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/ipc/Endpoint.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
-- 
GitLab