Bug 1478101 - Split AbortSignal in 2 classes: AbortSignal and AbortSignalImpl, r?bz
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 30 Jul 2018 11:34:51 +0200
changeset 1652169 0db2078c566874f922bb0429bc64918f6fa1b95d
parent 1652168 1ffd43faf297860db7ac92e6d901f819bd70ccc5
child 1652170 e0434e615d39be80fde303bfc062280fbc9f24c7
push id287771
push useramarchesini@mozilla.com
push dateMon, 30 Jul 2018 16:28:30 +0000
treeherdertry@efd4f85c2d3d [default view] [failures only]
reviewersbz
bugs1478101
milestone63.0a1
Bug 1478101 - Split AbortSignal in 2 classes: AbortSignal and AbortSignalImpl, r?bz
dom/abort/AbortSignal.cpp
dom/abort/AbortSignal.h
dom/fetch/Fetch.cpp
dom/fetch/Fetch.h
dom/fetch/FetchConsumer.cpp
dom/fetch/FetchConsumer.h
dom/fetch/FetchDriver.cpp
dom/fetch/FetchDriver.h
dom/fetch/FetchObserver.cpp
dom/fetch/FetchObserver.h
dom/fetch/Request.cpp
dom/fetch/Request.h
dom/fetch/Response.cpp
dom/fetch/Response.h
dom/webauthn/WebAuthnManager.cpp
dom/webauthn/WebAuthnManager.h
--- a/dom/abort/AbortSignal.cpp
+++ b/dom/abort/AbortSignal.cpp
@@ -8,86 +8,118 @@
 
 #include "AbortController.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/AbortSignalBinding.h"
 
 namespace mozilla {
 namespace dom {
 
+// AbortSignalImpl
+// ----------------------------------------------------------------------------
+
+AbortSignalImpl::AbortSignalImpl(bool aAborted)
+  : mAborted(aAborted)
+{}
+
+bool
+AbortSignalImpl::Aborted() const
+{
+  return mAborted;
+}
+
+void
+AbortSignalImpl::Abort()
+{
+  if (mAborted) {
+    return;
+  }
+
+  mAborted = true;
+
+  // Let's inform the followers.
+  for (uint32_t i = 0; i < mFollowers.Length(); ++i) {
+    mFollowers[i]->Abort();
+  }
+}
+
+void
+AbortSignalImpl::AddFollower(AbortFollower* aFollower)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aFollower);
+  if (!mFollowers.Contains(aFollower)) {
+    mFollowers.AppendElement(aFollower);
+  }
+}
+
+void
+AbortSignalImpl::RemoveFollower(AbortFollower* aFollower)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aFollower);
+  mFollowers.RemoveElement(aFollower);
+}
+
+// AbortSignal
+// ----------------------------------------------------------------------------
+
 AbortSignal::AbortSignal(nsIGlobalObject* aGlobalObject,
                          bool aAborted)
   : DOMEventTargetHelper(aGlobalObject)
-  , mAborted(aAborted)
-{}
-
-AbortSignal::AbortSignal(bool aAborted)
-  : mAborted(aAborted)
-{}
+  , mImpl(new AbortSignalImpl(aAborted))
+{
+}
 
 JSObject*
 AbortSignal::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return AbortSignal_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 bool
 AbortSignal::Aborted() const
 {
-  return mAborted;
+  return mImpl->Aborted();
 }
 
 void
 AbortSignal::Abort()
 {
-  MOZ_ASSERT(!mAborted);
-  mAborted = true;
+  if (mImpl->Aborted()) {
+    return;
+  }
 
-  // Let's inform the followers.
-  for (uint32_t i = 0; i < mFollowers.Length(); ++i) {
-    mFollowers[i]->Abort();
-  }
+  mImpl->Abort();
 
   EventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
 
   RefPtr<Event> event =
     Event::Constructor(this, NS_LITERAL_STRING("abort"), init);
   event->SetTrusted(true);
 
   DispatchEvent(*event);
 }
 
-void
-AbortSignal::AddFollower(AbortFollower* aFollower)
+AbortSignalImpl*
+AbortSignal::Impl() const
 {
-  MOZ_DIAGNOSTIC_ASSERT(aFollower);
-  if (!mFollowers.Contains(aFollower)) {
-    mFollowers.AppendElement(aFollower);
-  }
-}
-
-void
-AbortSignal::RemoveFollower(AbortFollower* aFollower)
-{
-  MOZ_DIAGNOSTIC_ASSERT(aFollower);
-  mFollowers.RemoveElement(aFollower);
+  return mImpl;
 }
 
 // AbortFollower
 // ----------------------------------------------------------------------------
 
 AbortFollower::~AbortFollower()
 {
   Unfollow();
 }
 
 void
-AbortFollower::Follow(AbortSignal* aSignal)
+AbortFollower::Follow(AbortSignalImpl* aSignal)
 {
   MOZ_DIAGNOSTIC_ASSERT(aSignal);
 
   Unfollow();
 
   mFollowingSignal = aSignal;
   aSignal->AddFollower(this);
 }
--- a/dom/abort/AbortSignal.h
+++ b/dom/abort/AbortSignal.h
@@ -7,68 +7,89 @@
 #ifndef mozilla_dom_AbortSignal_h
 #define mozilla_dom_AbortSignal_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 
 namespace mozilla {
 namespace dom {
 
-class AbortSignal;
+class AbortSignalImpl;
 
-// This class must be implemented by objects who want to follow a AbortSignal.
+// This class must be implemented by objects who want to follow a
+// AbortSignalImpl.
 class AbortFollower
 {
 public:
   virtual void Abort() = 0;
 
   void
-  Follow(AbortSignal* aSignal);
+  Follow(AbortSignalImpl* aSignal);
 
   void
   Unfollow();
 
   bool
   IsFollowing() const;
 
 protected:
   virtual ~AbortFollower();
 
-  RefPtr<AbortSignal> mFollowingSignal;
+  RefPtr<AbortSignalImpl> mFollowingSignal;
+};
+
+class AbortSignalImpl final : public AbortFollower
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(AbortSignalImpl);
+
+  AbortSignalImpl(bool aAborted);
+
+  bool
+  Aborted() const;
+
+  void
+  Abort() override;
+
+  void
+  AddFollower(AbortFollower* aFollower);
+
+  void
+  RemoveFollower(AbortFollower* aFollower);
+
+private:
+  ~AbortSignalImpl() = default;
+
+  // Raw pointers. AbortFollower unregisters itself in the DTOR.
+  nsTArray<AbortFollower*> mFollowers;
+
+  bool mAborted;
 };
 
 class AbortSignal final : public DOMEventTargetHelper
-                        , public AbortFollower
 {
 public:
   AbortSignal(nsIGlobalObject* aGlobalObject, bool aAborted);
-  explicit AbortSignal(bool aAborted);
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   bool
   Aborted() const;
 
   void
-  Abort() override;
+  Abort();
 
   IMPL_EVENT_HANDLER(abort);
 
-  void
-  AddFollower(AbortFollower* aFollower);
-
-  void
-  RemoveFollower(AbortFollower* aFollower);
+  AbortSignalImpl*
+  Impl() const;
 
 private:
   ~AbortSignal() = default;
 
-  // Raw pointers. AbortFollower unregisters itself in the DTOR.
-  nsTArray<AbortFollower*> mFollowers;
-
-  bool mAborted;
+  RefPtr<AbortSignalImpl> mImpl;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_AbortSignal_h
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -69,98 +69,100 @@ AbortStream(JSContext* aCx, JS::Handle<J
     return;
   }
 
   JS::ReadableStreamError(aCx, aStream, value);
 }
 
 } // anonymous
 
-// This class helps the proxying of AbortSignal changes cross threads.
+// This class helps the proxying of AbortSignalImpl changes cross threads.
 class AbortSignalProxy final : public AbortFollower
 {
   // This is created and released on the main-thread.
-  RefPtr<AbortSignal> mSignalMainThread;
+  RefPtr<AbortSignalImpl> mSignalImplMainThread;
 
   // The main-thread event target for runnable dispatching.
   nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
 
-  // This value is used only for the creation of AbortSignal on the
+  // This value is used only for the creation of AbortSignalImpl on the
   // main-thread. They are not updated.
   const bool mAborted;
 
-  // This runnable propagates changes from the AbortSignal on workers to the
-  // AbortSignal on main-thread.
+  // This runnable propagates changes from the AbortSignalImpl on workers to the
+  // AbortSignalImpl on main-thread.
   class AbortSignalProxyRunnable final : public Runnable
   {
     RefPtr<AbortSignalProxy> mProxy;
 
   public:
     explicit AbortSignalProxyRunnable(AbortSignalProxy* aProxy)
       : Runnable("dom::AbortSignalProxy::AbortSignalProxyRunnable")
       , mProxy(aProxy)
     {}
 
     NS_IMETHOD
     Run() override
     {
       MOZ_ASSERT(NS_IsMainThread());
-      AbortSignal* signal = mProxy->GetOrCreateSignalForMainThread();
-      signal->Abort();
+      AbortSignalImpl* signalImpl =
+        mProxy->GetOrCreateSignalImplForMainThread();
+      signalImpl->Abort();
       return NS_OK;
     }
   };
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbortSignalProxy)
 
-  AbortSignalProxy(AbortSignal* aSignal, nsIEventTarget* aMainThreadEventTarget)
+  AbortSignalProxy(AbortSignalImpl* aSignalImpl,
+                   nsIEventTarget* aMainThreadEventTarget)
     : mMainThreadEventTarget(aMainThreadEventTarget)
-    , mAborted(aSignal->Aborted())
+    , mAborted(aSignalImpl->Aborted())
   {
     MOZ_ASSERT(mMainThreadEventTarget);
-    Follow(aSignal);
+    Follow(aSignalImpl);
   }
 
   void
   Abort() override
   {
     RefPtr<AbortSignalProxyRunnable> runnable =
       new AbortSignalProxyRunnable(this);
     mMainThreadEventTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
   }
 
-  AbortSignal*
-  GetOrCreateSignalForMainThread()
+  AbortSignalImpl*
+  GetOrCreateSignalImplForMainThread()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    if (!mSignalMainThread) {
-      mSignalMainThread = new AbortSignal(mAborted);
+    if (!mSignalImplMainThread) {
+      mSignalImplMainThread = new AbortSignalImpl(mAborted);
     }
-    return mSignalMainThread;
+    return mSignalImplMainThread;
   }
 
-  AbortSignal*
-  GetSignalForTargetThread()
+  AbortSignalImpl*
+  GetSignalImplForTargetThread()
   {
     return mFollowingSignal;
   }
 
   void
   Shutdown()
   {
     Unfollow();
   }
 
 private:
   ~AbortSignalProxy()
   {
     NS_ProxyRelease(
-      "AbortSignalProxy::mSignalMainThread",
-      mMainThreadEventTarget, mSignalMainThread.forget());
+      "AbortSignalProxy::mSignalImplMainThread",
+      mMainThreadEventTarget, mSignalImplMainThread.forget());
   }
 };
 
 class WorkerFetchResolver final : public FetchDriverObserver
 {
   // Thread-safe:
   RefPtr<PromiseWorkerProxy> mPromiseProxy;
   RefPtr<AbortSignalProxy> mSignalProxy;
@@ -168,30 +170,31 @@ class WorkerFetchResolver final : public
   // Touched only on the worker thread.
   RefPtr<FetchObserver> mFetchObserver;
   RefPtr<WeakWorkerRef> mWorkerRef;
 
 public:
   // Returns null if worker is shutting down.
   static already_AddRefed<WorkerFetchResolver>
   Create(WorkerPrivate* aWorkerPrivate, Promise* aPromise,
-         AbortSignal* aSignal, FetchObserver* aObserver)
+         AbortSignalImpl* aSignalImpl, FetchObserver* aObserver)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
     RefPtr<PromiseWorkerProxy> proxy =
       PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
     if (!proxy) {
       return nullptr;
     }
 
     RefPtr<AbortSignalProxy> signalProxy;
-    if (aSignal) {
+    if (aSignalImpl) {
       signalProxy =
-        new AbortSignalProxy(aSignal, aWorkerPrivate->MainThreadEventTarget());
+        new AbortSignalProxy(aSignalImpl,
+                             aWorkerPrivate->MainThreadEventTarget());
     }
 
     RefPtr<WorkerFetchResolver> r =
       new WorkerFetchResolver(proxy, signalProxy, aObserver);
 
     RefPtr<WeakWorkerRef> workerRef =
       WeakWorkerRef::Create(aWorkerPrivate, [r]() {
         r->Shutdown(r->mWorkerRef->GetPrivate());
@@ -200,38 +203,38 @@ public:
       return nullptr;
     }
 
     r->mWorkerRef = std::move(workerRef);
 
     return r.forget();
   }
 
-  AbortSignal*
+  AbortSignalImpl*
   GetAbortSignalForMainThread()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!mSignalProxy) {
       return nullptr;
     }
 
-    return mSignalProxy->GetOrCreateSignalForMainThread();
+    return mSignalProxy->GetOrCreateSignalImplForMainThread();
   }
 
-  AbortSignal*
+  AbortSignalImpl*
   GetAbortSignalForTargetThread()
   {
     mPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
 
     if (!mSignalProxy) {
       return nullptr;
     }
 
-    return mSignalProxy->GetSignalForTargetThread();
+    return mSignalProxy->GetSignalImplForTargetThread();
   }
 
   PromiseWorkerProxy*
   PromiseProxy() const
   {
     MOZ_ASSERT(NS_IsMainThread());
     return mPromiseProxy;
   }
@@ -302,28 +305,28 @@ private:
   FlushConsoleReport() override;
 };
 
 class MainThreadFetchResolver final : public FetchDriverObserver
 {
   RefPtr<Promise> mPromise;
   RefPtr<Response> mResponse;
   RefPtr<FetchObserver> mFetchObserver;
-  RefPtr<AbortSignal> mSignal;
+  RefPtr<AbortSignalImpl> mSignalImpl;
   const bool mMozErrors;
 
   nsCOMPtr<nsILoadGroup> mLoadGroup;
 
   NS_DECL_OWNINGTHREAD
 public:
   MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver,
-                          AbortSignal* aSignal, bool aMozErrors)
+                          AbortSignalImpl* aSignalImpl, bool aMozErrors)
     : mPromise(aPromise)
     , mFetchObserver(aObserver)
-    , mSignal(aSignal)
+    , mSignalImpl(aSignalImpl)
     , mMozErrors(aMozErrors)
   {}
 
   void
   OnResponseAvailableInternal(InternalResponse* aResponse) override;
 
   void SetLoadGroup(nsILoadGroup* aLoadGroup)
   {
@@ -410,21 +413,22 @@ public:
         proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
       }
       fetch->SetWorkerScript(spec);
 
       fetch->SetClientInfo(mClientInfo);
       fetch->SetController(mController);
     }
 
-    RefPtr<AbortSignal> signal = mResolver->GetAbortSignalForMainThread();
+    RefPtr<AbortSignalImpl> signalImpl =
+      mResolver->GetAbortSignalForMainThread();
 
     // ...but release it before calling Fetch, because mResolver's callback can
     // be called synchronously and they want the mutex, too.
-    return fetch->Fetch(signal, mResolver);
+    return fetch->Fetch(signalImpl, mResolver);
   }
 };
 
 already_AddRefed<Promise>
 FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
              const RequestInit& aInit, CallerType aCallerType, ErrorResult& aRv)
 {
   RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
@@ -451,27 +455,27 @@ FetchRequest(nsIGlobalObject* aGlobal, c
   GlobalObject global(cx, jsGlobal);
 
   RefPtr<Request> request = Request::Constructor(global, aInput, aInit, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   RefPtr<InternalRequest> r = request->GetInternalRequest();
-  RefPtr<AbortSignal> signal = request->GetSignal();
+  RefPtr<AbortSignalImpl> signalImpl = request->GetSignalImpl();
 
-  if (signal && signal->Aborted()) {
+  if (signalImpl && signalImpl->Aborted()) {
     // Already aborted signal rejects immediately.
     aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
     return nullptr;
   }
 
   RefPtr<FetchObserver> observer;
   if (aInit.mObserve.WasPassed()) {
-    observer = new FetchObserver(aGlobal, signal);
+    observer = new FetchObserver(aGlobal, signalImpl);
     aInit.mObserve.Value().HandleEvent(*observer);
   }
 
   if (NS_IsMainThread()) {
     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
     nsCOMPtr<nsIDocument> doc;
     nsCOMPtr<nsILoadGroup> loadGroup;
     nsIPrincipal* principal;
@@ -500,40 +504,41 @@ FetchRequest(nsIGlobalObject* aGlobal, c
         aRv.Throw(rv);
         return nullptr;
       }
     }
 
     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
 
     RefPtr<MainThreadFetchResolver> resolver =
-      new MainThreadFetchResolver(p, observer, signal, request->MozErrors());
+      new MainThreadFetchResolver(p, observer, signalImpl,
+                                  request->MozErrors());
     RefPtr<FetchDriver> fetch =
       new FetchDriver(r, principal, loadGroup,
                       aGlobal->EventTargetFor(TaskCategory::Other),
                       nullptr, // PerformanceStorage
                       isTrackingFetch);
     fetch->SetDocument(doc);
     resolver->SetLoadGroup(loadGroup);
-    aRv = fetch->Fetch(signal, resolver);
+    aRv = fetch->Fetch(signalImpl, resolver);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   } else {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
 
     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0);
 
     if (worker->IsServiceWorker()) {
       r->SetSkipServiceWorker();
     }
 
     RefPtr<WorkerFetchResolver> resolver =
-      WorkerFetchResolver::Create(worker, p, signal, observer);
+      WorkerFetchResolver::Create(worker, p, signalImpl, observer);
     if (!resolver) {
       NS_WARNING("Could not keep the worker alive.");
       aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
       return nullptr;
     }
 
     Maybe<ClientInfo> clientInfo(worker->GetClientInfo());
     if (clientInfo.isNothing()) {
@@ -557,17 +562,17 @@ MainThreadFetchResolver::OnResponseAvail
   AssertIsOnMainThread();
 
   if (aResponse->Type() != ResponseType::Error) {
     if (mFetchObserver) {
       mFetchObserver->SetState(FetchState::Complete);
     }
 
     nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
-    mResponse = new Response(go, aResponse, mSignal);
+    mResponse = new Response(go, aResponse, mSignalImpl);
     mPromise->MaybeResolve(mResponse);
   } else {
     if (mFetchObserver) {
       mFetchObserver->SetState(FetchState::Errored);
     }
 
     if (mMozErrors) {
       mPromise->MaybeReject(aResponse->GetErrorCode());
@@ -1145,18 +1150,18 @@ template
 void
 FetchBody<Response>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
 
 template <class Derived>
 already_AddRefed<Promise>
 FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
                                 ErrorResult& aRv)
 {
-  RefPtr<AbortSignal> signal = DerivedClass()->GetSignal();
-  if (signal && signal->Aborted()) {
+  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
+  if (signalImpl && signalImpl->Aborted()) {
     aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
     return nullptr;
   }
 
   if (BodyUsed()) {
     aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
     return nullptr;
   }
@@ -1165,17 +1170,17 @@ FetchBody<Derived>::ConsumeBody(JSContex
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
 
   RefPtr<Promise> promise =
     FetchBodyConsumer<Derived>::Create(global, mMainThreadEventTarget, this,
-                                       signal, aType, aRv);
+                                       signalImpl, aType, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return promise.forget();
 }
 
 template
@@ -1219,27 +1224,27 @@ FetchBody<Response>::SetMimeType();
 template <class Derived>
 void
 FetchBody<Derived>::SetReadableStreamBody(JSContext* aCx, JSObject* aBody)
 {
   MOZ_ASSERT(!mReadableStreamBody);
   MOZ_ASSERT(aBody);
   mReadableStreamBody = aBody;
 
-  RefPtr<AbortSignal> signal = DerivedClass()->GetSignal();
-  if (!signal) {
+  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
+  if (!signalImpl) {
     return;
   }
 
-  bool aborted = signal->Aborted();
+  bool aborted = signalImpl->Aborted();
   if (aborted) {
     JS::Rooted<JSObject*> body(aCx, mReadableStreamBody);
     AbortStream(aCx, body);
   } else if (!IsFollowing()) {
-    Follow(signal);
+    Follow(signalImpl);
   }
 }
 
 template
 void
 FetchBody<Request>::SetReadableStreamBody(JSContext* aCx, JSObject* aBody);
 
 template
@@ -1277,22 +1282,22 @@ FetchBody<Derived>::GetBody(JSContext* a
   // If the body has been already consumed, we lock the stream.
   if (BodyUsed()) {
     LockStream(aCx, body, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
-  RefPtr<AbortSignal> signal = DerivedClass()->GetSignal();
-  if (signal) {
-    if (signal->Aborted()) {
+  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
+  if (signalImpl) {
+    if (signalImpl->Aborted()) {
       AbortStream(aCx, body);
     } else if (!IsFollowing()) {
-      Follow(signal);
+      Follow(signalImpl);
     }
   }
 
   mReadableStreamBody = body;
   aBodyOut.set(mReadableStreamBody);
 }
 
 template
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -244,18 +244,18 @@ public:
   }
 
   void
   MarkAsRead() override
   {
     mBodyUsed = true;
   }
 
-  virtual AbortSignal*
-  GetSignal() const = 0;
+  virtual AbortSignalImpl*
+  GetSignalImpl() const = 0;
 
   // AbortFollower
   void
   Abort() override;
 
 protected:
   nsCOMPtr<nsIGlobalObject> mOwner;
 
--- a/dom/fetch/FetchConsumer.cpp
+++ b/dom/fetch/FetchConsumer.cpp
@@ -333,17 +333,17 @@ NS_INTERFACE_MAP_END
 
 } // anonymous
 
 template <class Derived>
 /* static */ already_AddRefed<Promise>
 FetchBodyConsumer<Derived>::Create(nsIGlobalObject* aGlobal,
                                    nsIEventTarget* aMainThreadEventTarget,
                                    FetchBody<Derived>* aBody,
-                                   AbortSignal* aSignal,
+                                   AbortSignalImpl* aSignalImpl,
                                    FetchConsumeType aType,
                                    ErrorResult& aRv)
 {
   MOZ_ASSERT(aBody);
   MOZ_ASSERT(aMainThreadEventTarget);
 
   nsCOMPtr<nsIInputStream> bodyStream;
   aBody->DerivedClass()->GetBody(getter_AddRefs(bodyStream));
@@ -401,18 +401,18 @@ FetchBodyConsumer<Derived>::Create(nsIGl
 
   nsCOMPtr<nsIRunnable> r =
     new BeginConsumeBodyRunnable<Derived>(consumer, workerRef);
   aRv = aMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  if (aSignal) {
-    consumer->Follow(aSignal);
+  if (aSignalImpl) {
+    consumer->Follow(aSignalImpl);
   }
 
   return promise.forget();
 }
 
 template <class Derived>
 void
 FetchBodyConsumer<Derived>::ReleaseObject()
--- a/dom/fetch/FetchConsumer.h
+++ b/dom/fetch/FetchConsumer.h
@@ -34,17 +34,17 @@ class FetchBodyConsumer final : public n
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   static already_AddRefed<Promise>
   Create(nsIGlobalObject* aGlobal,
          nsIEventTarget* aMainThreadEventTarget,
          FetchBody<Derived>* aBody,
-         AbortSignal* aSignal,
+         AbortSignalImpl* aSignalImpl,
          FetchConsumeType aType,
          ErrorResult& aRv);
 
   void
   ReleaseObject();
 
   void
   BeginConsumeBodyMainThread(ThreadSafeWorkerRef* aWorkerRef);
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -357,17 +357,17 @@ FetchDriver::~FetchDriver()
   AssertIsOnMainThread();
 
   // We assert this since even on failures, we should call
   // FailWithNetworkError().
   MOZ_ASSERT(mResponseAvailableCalled);
 }
 
 nsresult
-FetchDriver::Fetch(AbortSignal* aSignal, FetchDriverObserver* aObserver)
+FetchDriver::Fetch(AbortSignalImpl* aSignalImpl, FetchDriverObserver* aObserver)
 {
   AssertIsOnMainThread();
 #ifdef DEBUG
   MOZ_ASSERT(!mFetchCalled);
   mFetchCalled = true;
 #endif
 
   mObserver = aObserver;
@@ -386,23 +386,23 @@ FetchDriver::Fetch(AbortSignal* aSignal,
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   mRequest->SetPrincipalInfo(std::move(principalInfo));
 
   // If the signal is aborted, it's time to inform the observer and terminate
   // the operation.
-  if (aSignal) {
-    if (aSignal->Aborted()) {
+  if (aSignalImpl) {
+    if (aSignalImpl->Aborted()) {
       Abort();
       return NS_OK;
     }
 
-    Follow(aSignal);
+    Follow(aSignalImpl);
   }
 
   rv = HttpFetch(mRequest->GetPreferredAlternativeDataType());
   if (NS_FAILED(rv)) {
     FailWithNetworkError(rv);
   }
 
   // Any failure is handled by FailWithNetworkError notifying the aObserver.
--- a/dom/fetch/FetchDriver.h
+++ b/dom/fetch/FetchDriver.h
@@ -108,17 +108,17 @@ public:
 
   FetchDriver(InternalRequest* aRequest,
               nsIPrincipal* aPrincipal,
               nsILoadGroup* aLoadGroup,
               nsIEventTarget* aMainThreadEventTarget,
               PerformanceStorage* aPerformanceStorage,
               bool aIsTrackingFetch);
 
-  nsresult Fetch(AbortSignal* aSignal,
+  nsresult Fetch(AbortSignalImpl* aSignalImpl,
                  FetchDriverObserver* aObserver);
 
   void
   SetDocument(nsIDocument* aDocument);
 
   void
   SetClientInfo(const ClientInfo& aClientInfo);
 
--- a/dom/fetch/FetchObserver.cpp
+++ b/dom/fetch/FetchObserver.cpp
@@ -22,22 +22,22 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FetchObserver)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(FetchObserver, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(FetchObserver, DOMEventTargetHelper)
 
 FetchObserver::FetchObserver(nsIGlobalObject* aGlobal,
-                             AbortSignal* aSignal)
+                             AbortSignalImpl* aSignalImpl)
   : DOMEventTargetHelper(aGlobal)
   , mState(FetchState::Requesting)
 {
-  if (aSignal) {
-    Follow(aSignal);
+  if (aSignalImpl) {
+    Follow(aSignalImpl);
   }
 }
 
 JSObject*
 FetchObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return FetchObserver_Binding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/fetch/FetchObserver.h
+++ b/dom/fetch/FetchObserver.h
@@ -16,17 +16,17 @@ namespace dom {
 
 class FetchObserver final : public DOMEventTargetHelper
                           , public AbortFollower
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchObserver, DOMEventTargetHelper)
 
-  FetchObserver(nsIGlobalObject* aGlobal, AbortSignal* aSignal);
+  FetchObserver(nsIGlobalObject* aGlobal, AbortSignalImpl* aSignalImpl);
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   FetchState
   State() const;
 
   IMPL_EVENT_HANDLER(statechange);
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -23,25 +23,25 @@ namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Request)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Request)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Request)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Request)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamBody)
   MOZ_DIAGNOSTIC_ASSERT(!tmp->mReadableStreamReader);
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamReader)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
@@ -59,19 +59,19 @@ Request::Request(nsIGlobalObject* aOwner
   MOZ_ASSERT(aRequest->Headers()->Guard() == HeadersGuardEnum::Immutable ||
              aRequest->Headers()->Guard() == HeadersGuardEnum::Request ||
              aRequest->Headers()->Guard() == HeadersGuardEnum::Request_no_cors);
   SetMimeType();
 
   if (aSignal) {
     // If we don't have a signal as argument, we will create it when required by
     // content, otherwise the Request's signal must follow what has been passed.
-    mSignal = new AbortSignal(aSignal->Aborted());
+    mSignal = new AbortSignal(aOwner, aSignal->Aborted());
     if (!mSignal->Aborted()) {
-      mSignal->Follow(aSignal);
+      mSignal->Impl()->Follow(aSignal->Impl());
     }
   }
 }
 
 Request::~Request()
 {
 }
 
@@ -621,22 +621,22 @@ Request::Headers_()
 
   return mHeaders;
 }
 
 AbortSignal*
 Request::GetOrCreateSignal()
 {
   if (!mSignal) {
-    mSignal = new AbortSignal(false);
+    mSignal = new AbortSignal(mOwner, false);
   }
 
   return mSignal;
 }
 
-AbortSignal*
-Request::GetSignal() const
+AbortSignalImpl*
+Request::GetSignalImpl() const
 {
-  return mSignal;
+  return mSignal ? mSignal->Impl() : nullptr;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -162,19 +162,19 @@ public:
   GetPrincipalInfo() const
   {
     return mRequest->GetPrincipalInfo();
   }
 
   AbortSignal*
   GetOrCreateSignal();
 
-  // This can return a null AbortSignal.
-  AbortSignal*
-  GetSignal() const override;
+  // This can return a null AbortSignalImpl.
+  AbortSignalImpl*
+  GetSignalImpl() const override;
 
 private:
   ~Request();
 
   RefPtr<InternalRequest> mRequest;
 
   // Lazily created.
   RefPtr<Headers> mHeaders;
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -32,49 +32,47 @@ namespace dom {
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Response)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Response)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Response)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Response)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchStreamReader)
 
   tmp->mReadableStreamBody = nullptr;
   tmp->mReadableStreamReader = nullptr;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Response)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchStreamReader)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Response)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamBody)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamReader)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 Response::Response(nsIGlobalObject* aGlobal,
                    InternalResponse* aInternalResponse,
-                   AbortSignal* aSignal)
+                   AbortSignalImpl* aSignalImpl)
   : FetchBody<Response>(aGlobal)
   , mInternalResponse(aInternalResponse)
-  , mSignal(aSignal)
+  , mSignalImpl(aSignalImpl)
 {
   MOZ_ASSERT(aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Immutable ||
              aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Response);
   SetMimeType();
 
   mozilla::HoldJSObjects(this);
 }
 
@@ -339,17 +337,17 @@ Response::Clone(JSContext* aCx, ErrorRes
   MOZ_ASSERT_IF(body, streamReader);
   MOZ_ASSERT_IF(body, inputStream);
 
   RefPtr<InternalResponse> ir =
     mInternalResponse->Clone(body
       ? InternalResponse::eDontCloneInputStream
       : InternalResponse::eCloneInputStream);
 
-  RefPtr<Response> response = new Response(mOwner, ir, mSignal);
+  RefPtr<Response> response = new Response(mOwner, ir, mSignalImpl);
 
   if (body) {
     // Maybe we have a body, but we receive null from MaybeTeeReadableStreamBody
     // if this body is a native stream.   In this case the InternalResponse will
     // have a clone of the native body and the ReadableStream will be created
     // lazily if needed.
     response->SetReadableStreamBody(aCx, body);
     response->mFetchStreamReader = streamReader;
@@ -382,17 +380,17 @@ Response::CloneUnfiltered(JSContext* aCx
   MOZ_ASSERT_IF(body, inputStream);
 
   RefPtr<InternalResponse> clone =
     mInternalResponse->Clone(body
       ? InternalResponse::eDontCloneInputStream
       : InternalResponse::eCloneInputStream);
 
   RefPtr<InternalResponse> ir = clone->Unfiltered();
-  RefPtr<Response> ref = new Response(mOwner, ir, mSignal);
+  RefPtr<Response> ref = new Response(mOwner, ir, mSignalImpl);
 
   if (body) {
     // Maybe we have a body, but we receive null from MaybeTeeReadableStreamBody
     // if this body is a native stream.   In this case the InternalResponse will
     // have a clone of the native body and the ReadableStream will be created
     // lazily if needed.
     ref->SetReadableStreamBody(aCx, body);
     ref->mFetchStreamReader = streamReader;
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -29,17 +29,17 @@ class Response final : public nsISupport
                      , public FetchBody<Response>
                      , public nsWrapperCache
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response)
 
 public:
   Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse,
-           AbortSignal* aSignal);
+           AbortSignalImpl* aSignalImpl);
 
   Response(const Response& aOther) = delete;
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return Response_Binding::Wrap(aCx, this, aGivenProto);
   }
@@ -135,27 +135,27 @@ public:
   CloneUnfiltered(JSContext* aCx, ErrorResult& aRv);
 
   void
   SetBody(nsIInputStream* aBody, int64_t aBodySize);
 
   already_AddRefed<InternalResponse>
   GetInternalResponse() const;
 
-  AbortSignal*
-  GetSignal() const override
+  AbortSignalImpl*
+  GetSignalImpl() const override
   {
-    return mSignal;
+    return mSignalImpl;
   }
 
 private:
   ~Response();
 
   RefPtr<InternalResponse> mInternalResponse;
   // Lazily created
   RefPtr<Headers> mHeaders;
-  RefPtr<AbortSignal> mSignal;
+  RefPtr<AbortSignalImpl> mSignalImpl;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Response_h
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -390,24 +390,24 @@ WebAuthnManager::MakeCredential(const Pu
                                   challenge,
                                   clientDataJSON,
                                   adjustedTimeout,
                                   excludeList,
                                   extra);
 
   ListenForVisibilityEvents();
 
-  AbortSignal* signal = nullptr;
+  AbortSignalImpl* signalImpl = nullptr;
   if (aSignal.WasPassed()) {
-    signal = &aSignal.Value();
-    Follow(signal);
+    signalImpl = aSignal.Value().Impl();
+    Follow(signalImpl);
   }
 
   MOZ_ASSERT(mTransaction.isNothing());
-  mTransaction = Some(WebAuthnTransaction(promise, signal));
+  mTransaction = Some(WebAuthnTransaction(promise, signalImpl));
   mChild->SendRequestRegister(mTransaction.ref().mId, info);
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 WebAuthnManager::GetAssertion(const PublicKeyCredentialRequestOptions& aOptions,
                               const Optional<OwningNonNull<AbortSignal>>& aSignal)
@@ -570,24 +570,24 @@ WebAuthnManager::GetAssertion(const Publ
                                 challenge,
                                 clientDataJSON,
                                 adjustedTimeout,
                                 allowList,
                                 extra);
 
   ListenForVisibilityEvents();
 
-  AbortSignal* signal = nullptr;
+  AbortSignalImpl* signalImpl = nullptr;
   if (aSignal.WasPassed()) {
-    signal = &aSignal.Value();
-    Follow(signal);
+    signalImpl = aSignal.Value().Impl();
+    Follow(signalImpl);
   }
 
   MOZ_ASSERT(mTransaction.isNothing());
-  mTransaction = Some(WebAuthnTransaction(promise, signal));
+  mTransaction = Some(WebAuthnTransaction(promise, signalImpl));
   mChild->SendRequestSign(mTransaction.ref().mId, info);
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 WebAuthnManager::Store(const Credential& aCredential)
 {
--- a/dom/webauthn/WebAuthnManager.h
+++ b/dom/webauthn/WebAuthnManager.h
@@ -43,30 +43,26 @@
 
 namespace mozilla {
 namespace dom {
 
 class WebAuthnTransaction
 {
 public:
   WebAuthnTransaction(const RefPtr<Promise>& aPromise,
-                      AbortSignal* aSignal)
+                      AbortSignalImpl* aSignalImpl)
     : mPromise(aPromise)
-    , mSignal(aSignal)
     , mId(NextId())
   {
     MOZ_ASSERT(mId > 0);
   }
 
   // JS Promise representing the transaction status.
   RefPtr<Promise> mPromise;
 
-  // An optional AbortSignal instance.
-  RefPtr<AbortSignal> mSignal;
-
   // Unique transaction id.
   uint64_t mId;
 
 private:
   // Generates a unique id for new transactions. This doesn't have to be unique
   // forever, it's sufficient to differentiate between temporally close
   // transactions, where messages can intersect. Can overflow.
   static uint64_t NextId() {