Bug 1434701 P11 Make ServiceWorkerDescriptor use an Inner class with main and worker thread implementations. r=asuth
authorBen Kelly <ben@wanderview.com>
Wed, 14 Feb 2018 14:23:17 -0500
changeset 403877 405e4d2846f33353cac80f9ec1df900b7c576053
parent 403876 142e6dc5ea6d8744c1d231986e01fec8b5f4df58
child 403878 be2a8b7e6ed2de38e6240a3cc288b4e1cb495da2
push id33445
push userapavel@mozilla.com
push dateThu, 15 Feb 2018 10:27:00 +0000
treeherdermozilla-central@9b69cc60e584 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1434701
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1434701 P11 Make ServiceWorkerDescriptor use an Inner class with main and worker thread implementations. r=asuth
dom/serviceworkers/ServiceWorkerRegistration.cpp
dom/serviceworkers/ServiceWorkerRegistration.h
dom/serviceworkers/ServiceWorkerRegistrationImpl.cpp
dom/serviceworkers/ServiceWorkerRegistrationImpl.h
--- a/dom/serviceworkers/ServiceWorkerRegistration.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistration.cpp
@@ -2,74 +2,109 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ServiceWorkerRegistration.h"
 
 #include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PushManager.h"
+#include "mozilla/dom/ServiceWorker.h"
 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupportsPrimitives.h"
 #include "nsPIDOMWindow.h"
 #include "ServiceWorkerRegistrationImpl.h"
 
 namespace mozilla {
 namespace dom {
 
+NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistration,
+                                   DOMEventTargetHelper,
+                                   mInstallingWorker,
+                                   mWaitingWorker,
+                                   mActiveWorker,
+                                   mPushManager);
+
 NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerRegistration)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
-ServiceWorkerRegistration::ServiceWorkerRegistration(nsPIDOMWindowInner* aWindow,
-                                                     const ServiceWorkerRegistrationDescriptor& aDescriptor)
-  : DOMEventTargetHelper(aWindow)
+ServiceWorkerRegistration::ServiceWorkerRegistration(nsIGlobalObject* aGlobal,
+                                                     const ServiceWorkerRegistrationDescriptor& aDescriptor,
+                                                     ServiceWorkerRegistration::Inner* aInner)
+  : DOMEventTargetHelper(aGlobal)
   , mDescriptor(aDescriptor)
+  , mInner(aInner)
 {
+  MOZ_DIAGNOSTIC_ASSERT(mInner);
+  UpdateState(mDescriptor);
+  mInner->SetServiceWorkerRegistration(this);
+}
+
+ServiceWorkerRegistration::~ServiceWorkerRegistration()
+{
+  if (mInner) {
+    mInner->ClearServiceWorkerRegistration(this);
+  }
 }
 
 JSObject*
 ServiceWorkerRegistration::WrapObject(JSContext* aCx,
                                       JS::Handle<JSObject*> aGivenProto)
 {
   return ServiceWorkerRegistrationBinding::Wrap(aCx, this, aGivenProto);
 }
 
 /* static */ already_AddRefed<ServiceWorkerRegistration>
 ServiceWorkerRegistration::CreateForMainThread(nsPIDOMWindowInner* aWindow,
                                                const ServiceWorkerRegistrationDescriptor& aDescriptor)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(NS_IsMainThread());
 
+  nsCOMPtr<nsIGlobalObject> global(do_QueryInterface(aWindow));
+
+  RefPtr<Inner> inner = new ServiceWorkerRegistrationMainThread(aDescriptor);
+
   RefPtr<ServiceWorkerRegistration> registration =
-    new ServiceWorkerRegistrationMainThread(aWindow, aDescriptor);
+    new ServiceWorkerRegistration(global, aDescriptor, inner);
 
   return registration.forget();
 }
 
 /* static */ already_AddRefed<ServiceWorkerRegistration>
 ServiceWorkerRegistration::CreateForWorker(WorkerPrivate* aWorkerPrivate,
                                            const ServiceWorkerRegistrationDescriptor& aDescriptor)
 {
   MOZ_ASSERT(aWorkerPrivate);
   aWorkerPrivate->AssertIsOnWorkerThread();
 
-  NS_ConvertUTF8toUTF16 scope(aDescriptor.Scope());
+  RefPtr<Inner> inner =
+    new ServiceWorkerRegistrationWorkerThread(aWorkerPrivate, aDescriptor);
 
   RefPtr<ServiceWorkerRegistration> registration =
-    new ServiceWorkerRegistrationWorkerThread(aWorkerPrivate, aDescriptor);
+    new ServiceWorkerRegistration(aWorkerPrivate->GlobalScope(), aDescriptor,
+                                  inner);
 
   return registration.forget();
 }
 
+void
+ServiceWorkerRegistration::DisconnectFromOwner()
+{
+  mInner->ClearServiceWorkerRegistration(this);
+  mInner = nullptr;
+  DOMEventTargetHelper::DisconnectFromOwner();
+}
+
 already_AddRefed<ServiceWorker>
 ServiceWorkerRegistration::GetInstalling() const
 {
   RefPtr<ServiceWorker> ref = mInstallingWorker;
   return ref.forget();
 }
 
 already_AddRefed<ServiceWorker>
@@ -137,10 +172,71 @@ ServiceWorkerRegistration::GetScope(nsAS
 }
 
 ServiceWorkerUpdateViaCache
 ServiceWorkerRegistration::GetUpdateViaCache(ErrorResult& aRv) const
 {
   return mDescriptor.UpdateViaCache();
 }
 
+already_AddRefed<Promise>
+ServiceWorkerRegistration::Update(ErrorResult& aRv)
+{
+  if (!mInner) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  return mInner->Update(aRv);
+}
+
+already_AddRefed<Promise>
+ServiceWorkerRegistration::Unregister(ErrorResult& aRv)
+{
+  if (!mInner) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  return mInner->Unregister(aRv);
+}
+
+already_AddRefed<PushManager>
+ServiceWorkerRegistration::GetPushManager(JSContext* aCx, ErrorResult& aRv)
+{
+  if (!mInner) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  if (!mPushManager) {
+    mPushManager = mInner->GetPushManager(aCx, aRv);
+    if (aRv.Failed()) {
+      return nullptr;
+    }
+  }
+  RefPtr<PushManager> ret = mPushManager;
+  return ret.forget();
+}
+
+already_AddRefed<Promise>
+ServiceWorkerRegistration::ShowNotification(JSContext* aCx,
+                                            const nsAString& aTitle,
+                                            const NotificationOptions& aOptions,
+                                            ErrorResult& aRv)
+{
+  if (!mInner) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  return mInner->ShowNotification(aCx, aTitle, aOptions, aRv);
+}
+
+already_AddRefed<Promise>
+ServiceWorkerRegistration::GetNotifications(const GetNotificationOptions& aOptions,
+                                            ErrorResult& aRv)
+{
+  if (!mInner) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  return mInner->GetNotifications(aOptions, aRv);
+}
+
 } // dom namespace
 } // mozilla namespace
--- a/dom/serviceworkers/ServiceWorkerRegistration.h
+++ b/dom/serviceworkers/ServiceWorkerRegistration.h
@@ -4,51 +4,85 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ServiceWorkerRegistration_h
 #define mozilla_dom_ServiceWorkerRegistration_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/DOMPrefs.h"
-#include "mozilla/dom/ServiceWorker.h"
 #include "mozilla/dom/ServiceWorkerBinding.h"
 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
 
 // Support for Notification API extension.
 #include "mozilla/dom/NotificationBinding.h"
 
-class nsPIDOMWindowInner;
+class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 class Promise;
 class PushManager;
 class WorkerPrivate;
+class ServiceWorker;
 
-class ServiceWorkerRegistration : public DOMEventTargetHelper
+class ServiceWorkerRegistration final : public DOMEventTargetHelper
 {
 public:
+  class Inner
+  {
+  public:
+    NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
+
+    virtual void
+    SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) = 0;
+
+    virtual void
+    ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) = 0;
+
+    virtual already_AddRefed<Promise>
+    Update(ErrorResult& aRv) = 0;
+
+    virtual already_AddRefed<Promise>
+    Unregister(ErrorResult& aRv) = 0;
+
+    virtual already_AddRefed<Promise>
+    ShowNotification(JSContext* aCx,
+                     const nsAString& aTitle,
+                     const NotificationOptions& aOptions,
+                     ErrorResult& aRv) = 0;
+
+    virtual already_AddRefed<Promise>
+    GetNotifications(const GetNotificationOptions& aOptions,
+                     ErrorResult& aRv) = 0;
+
+    virtual already_AddRefed<PushManager>
+    GetPushManager(JSContext* aCx, ErrorResult& aRv) = 0;
+  };
+
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
 
   IMPL_EVENT_HANDLER(updatefound)
 
   static already_AddRefed<ServiceWorkerRegistration>
   CreateForMainThread(nsPIDOMWindowInner* aWindow,
                       const ServiceWorkerRegistrationDescriptor& aDescriptor);
 
   static already_AddRefed<ServiceWorkerRegistration>
   CreateForWorker(WorkerPrivate* aWorkerPrivate,
                   const ServiceWorkerRegistrationDescriptor& aDescriptor);
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
+  void DisconnectFromOwner() override;
+
   already_AddRefed<ServiceWorker>
   GetInstalling() const;
 
   already_AddRefed<ServiceWorker>
   GetWaiting() const;
 
   already_AddRefed<ServiceWorker>
   GetActive() const;
@@ -60,45 +94,47 @@ public:
   MatchesDescriptor(const ServiceWorkerRegistrationDescriptor& aDescriptor) const;
 
   void
   GetScope(nsAString& aScope) const;
 
   ServiceWorkerUpdateViaCache
   GetUpdateViaCache(ErrorResult& aRv) const;
 
-  virtual already_AddRefed<Promise>
-  Update(ErrorResult& aRv) = 0;
+  already_AddRefed<Promise>
+  Update(ErrorResult& aRv);
 
-  virtual already_AddRefed<Promise>
-  Unregister(ErrorResult& aRv) = 0;
+  already_AddRefed<Promise>
+  Unregister(ErrorResult& aRv);
 
-  virtual already_AddRefed<PushManager>
-  GetPushManager(JSContext* aCx, ErrorResult& aRv) = 0;
+  already_AddRefed<PushManager>
+  GetPushManager(JSContext* aCx, ErrorResult& aRv);
 
-  virtual already_AddRefed<Promise>
+  already_AddRefed<Promise>
   ShowNotification(JSContext* aCx,
                    const nsAString& aTitle,
                    const NotificationOptions& aOptions,
-                   ErrorResult& aRv) = 0;
+                   ErrorResult& aRv);
 
-  virtual already_AddRefed<Promise>
+  already_AddRefed<Promise>
   GetNotifications(const GetNotificationOptions& aOptions,
-                   ErrorResult& aRv) = 0;
+                   ErrorResult& aRv);
 
-protected:
-  ServiceWorkerRegistration(nsPIDOMWindowInner* aWindow,
-                            const ServiceWorkerRegistrationDescriptor& aDescriptor);
+private:
+  ServiceWorkerRegistration(nsIGlobalObject* aGlobal,
+                            const ServiceWorkerRegistrationDescriptor& aDescriptor,
+                            Inner* aInner);
 
-  virtual ~ServiceWorkerRegistration()
-  { }
+  ~ServiceWorkerRegistration();
 
   ServiceWorkerRegistrationDescriptor mDescriptor;
+  RefPtr<Inner> mInner;
   RefPtr<ServiceWorker> mInstallingWorker;
   RefPtr<ServiceWorker> mWaitingWorker;
   RefPtr<ServiceWorker> mActiveWorker;
+  RefPtr<PushManager> mPushManager;
 };
 
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_ServiceWorkerRegistration_h */
--- a/dom/serviceworkers/ServiceWorkerRegistrationImpl.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrationImpl.cpp
@@ -34,43 +34,28 @@
 #include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 ////////////////////////////////////////////////////
 // Main Thread implementation
 
-NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistrationMainThread, ServiceWorkerRegistration)
-NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistrationMainThread, ServiceWorkerRegistration)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerRegistrationMainThread)
-NS_INTERFACE_MAP_END_INHERITING(ServiceWorkerRegistration)
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistrationMainThread,
-                                   ServiceWorkerRegistration,
-                                   mPushManager,
-                                   mInstallingWorker, mWaitingWorker, mActiveWorker);
-
-ServiceWorkerRegistrationMainThread::ServiceWorkerRegistrationMainThread(nsPIDOMWindowInner* aWindow,
-                                                                         const ServiceWorkerRegistrationDescriptor& aDescriptor)
-  : ServiceWorkerRegistration(aWindow, aDescriptor)
+ServiceWorkerRegistrationMainThread::ServiceWorkerRegistrationMainThread(const ServiceWorkerRegistrationDescriptor& aDescriptor)
+  : mOuter(nullptr)
   , mScope(NS_ConvertUTF8toUTF16(aDescriptor.Scope()))
   , mListeningForEvents(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aWindow);
-  UpdateState(aDescriptor);
-  StartListeningForEvents();
 }
 
 ServiceWorkerRegistrationMainThread::~ServiceWorkerRegistrationMainThread()
 {
-  StopListeningForEvents();
-  MOZ_ASSERT(!mListeningForEvents);
+  MOZ_DIAGNOSTIC_ASSERT(!mListeningForEvents);
+  MOZ_DIAGNOSTIC_ASSERT(!mOuter);
 }
 
 // XXXnsm, maybe this can be optimized to only add when a event handler is
 // registered.
 void
 ServiceWorkerRegistrationMainThread::StartListeningForEvents()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -95,40 +80,58 @@ ServiceWorkerRegistrationMainThread::Sto
     swm->RemoveRegistrationEventListener(mScope, this);
   }
   mListeningForEvents = false;
 }
 
 void
 ServiceWorkerRegistrationMainThread::UpdateFound()
 {
-  DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
+  mOuter->DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
 }
 
 void
 ServiceWorkerRegistrationMainThread::UpdateState(const ServiceWorkerRegistrationDescriptor& aDescriptor)
 {
-  ServiceWorkerRegistration::UpdateState(aDescriptor);
+  mOuter->UpdateState(aDescriptor);
 }
 
 void
 ServiceWorkerRegistrationMainThread::RegistrationRemoved()
 {
   // If the registration is being removed completely, remove it from the
   // window registration hash table so that a new registration would get a new
   // wrapper JS object.
-  if (nsCOMPtr<nsPIDOMWindowInner> window = GetOwner()) {
+  if (nsCOMPtr<nsPIDOMWindowInner> window = mOuter->GetOwner()) {
     window->InvalidateServiceWorkerRegistration(mScope);
   }
 }
 
 bool
 ServiceWorkerRegistrationMainThread::MatchesDescriptor(const ServiceWorkerRegistrationDescriptor& aDescriptor)
 {
-  return ServiceWorkerRegistration::MatchesDescriptor(aDescriptor);
+  return mOuter->MatchesDescriptor(aDescriptor);
+}
+
+void
+ServiceWorkerRegistrationMainThread::SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aReg);
+  MOZ_DIAGNOSTIC_ASSERT(!mOuter);
+  mOuter = aReg;
+  StartListeningForEvents();
+}
+
+void
+ServiceWorkerRegistrationMainThread::ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg)
+{
+  MOZ_DIAGNOSTIC_ASSERT(mOuter);
+  MOZ_DIAGNOSTIC_ASSERT(mOuter == aReg);
+  StopListeningForEvents();
+  mOuter = nullptr;
 }
 
 namespace {
 
 void
 UpdateInternal(nsIPrincipal* aPrincipal,
                const nsAString& aScope,
                ServiceWorkerUpdateFinishCallback* aCallback)
@@ -509,53 +512,53 @@ public:
   }
 };
 } // namespace
 
 already_AddRefed<Promise>
 ServiceWorkerRegistrationMainThread::Update(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(GetOwner());
+  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mOuter->GetOwner());
   if (!go) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   RefPtr<Promise> promise = Promise::Create(go, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
+  nsCOMPtr<nsIDocument> doc = mOuter->GetOwner()->GetExtantDoc();
   MOZ_ASSERT(doc);
 
   RefPtr<MainThreadUpdateCallback> cb =
-    new MainThreadUpdateCallback(GetOwner(), promise);
+    new MainThreadUpdateCallback(mOuter->GetOwner(), promise);
   UpdateInternal(doc->NodePrincipal(), mScope, cb);
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerRegistrationMainThread::Unregister(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(GetOwner());
+  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mOuter->GetOwner());
   if (!go) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   // Although the spec says that the same-origin checks should also be done
   // asynchronously, we do them in sync because the Promise created by the
   // WebIDL infrastructure due to a returned error will be resolved
   // asynchronously. We aren't making any internal state changes in these
   // checks, so ordering of multiple calls is not affected.
-  nsCOMPtr<nsIDocument> document = GetOwner()->GetExtantDoc();
+  nsCOMPtr<nsIDocument> document = mOuter->GetOwner()->GetExtantDoc();
   if (!document) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> scopeURI;
   nsCOMPtr<nsIURI> baseURI = document->GetBaseURI();
   // "If the origin of scope is not client's origin..."
@@ -582,17 +585,17 @@ ServiceWorkerRegistrationMainThread::Unr
   nsCOMPtr<nsIServiceWorkerManager> swm =
     mozilla::services::GetServiceWorkerManager();
 
   RefPtr<Promise> promise = Promise::Create(go, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  RefPtr<UnregisterCallback> cb = new UnregisterCallback(GetOwner(), promise);
+  RefPtr<UnregisterCallback> cb = new UnregisterCallback(mOuter->GetOwner(), promise);
 
   NS_ConvertUTF8toUTF16 scope(uriSpec);
   aRv = swm->Unregister(documentPrincipal, cb, scope);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   return promise.forget();
@@ -601,29 +604,29 @@ ServiceWorkerRegistrationMainThread::Unr
 // Notification API extension.
 already_AddRefed<Promise>
 ServiceWorkerRegistrationMainThread::ShowNotification(JSContext* aCx,
                                                       const nsAString& aTitle,
                                                       const NotificationOptions& aOptions,
                                                       ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
+  nsCOMPtr<nsPIDOMWindowInner> window = mOuter->GetOwner();
   if (NS_WARN_IF(!window)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   if (NS_WARN_IF(!doc)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  RefPtr<ServiceWorker> worker = GetActive();
+  RefPtr<ServiceWorker> worker = mOuter->GetActive();
   if (!worker) {
     aRv.ThrowTypeError<MSG_NO_ACTIVE_WORKER>(mScope);
     return nullptr;
   }
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
   RefPtr<Promise> p =
     Notification::ShowPersistentNotification(aCx, global, mScope, aTitle,
@@ -634,76 +637,73 @@ ServiceWorkerRegistrationMainThread::Sho
 
   return p.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerRegistrationMainThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
+  nsCOMPtr<nsPIDOMWindowInner> window = mOuter->GetOwner();
   if (NS_WARN_IF(!window)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
   return Notification::Get(window, aOptions, mScope, aRv);
 }
 
 already_AddRefed<PushManager>
 ServiceWorkerRegistrationMainThread::GetPushManager(JSContext* aCx,
                                                     ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!mPushManager) {
-    nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
+  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(mOuter->GetOwner());
 
-    if (!globalObject) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
-    }
-
-    GlobalObject global(aCx, globalObject->GetGlobalJSObject());
-    mPushManager = PushManager::Constructor(global, mScope, aRv);
-    if (aRv.Failed()) {
-      return nullptr;
-    }
+  if (!globalObject) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  RefPtr<PushManager> ret = mPushManager;
+  GlobalObject global(aCx, globalObject->GetGlobalJSObject());
+  RefPtr<PushManager> ret = PushManager::Constructor(global, mScope, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
   return ret.forget();
 }
 
 ////////////////////////////////////////////////////
 // Worker Thread implementation
 
 class WorkerListener final : public ServiceWorkerRegistrationListener
 {
   // Accessed on the main thread.
   WorkerPrivate* mWorkerPrivate;
-  nsString mScope;
+  const nsString mScope;
   bool mListeningForEvents;
 
   // Accessed on the worker thread.
   ServiceWorkerRegistrationWorkerThread* mRegistration;
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerListener, override)
 
   WorkerListener(WorkerPrivate* aWorkerPrivate,
-                 ServiceWorkerRegistrationWorkerThread* aReg)
+                 ServiceWorkerRegistrationWorkerThread* aReg,
+                 const nsAString& aScope)
     : mWorkerPrivate(aWorkerPrivate)
+    , mScope(aScope)
     , mListeningForEvents(false)
     , mRegistration(aReg)
   {
     MOZ_ASSERT(mWorkerPrivate);
     mWorkerPrivate->AssertIsOnWorkerThread();
     MOZ_ASSERT(mRegistration);
-    // Copy scope so we can return it on the main thread.
-    mRegistration->GetScope(mScope);
   }
 
   void
   StartListeningForEvents()
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(!mListeningForEvents);
     MOZ_ASSERT(mWorkerPrivate);
@@ -785,51 +785,47 @@ public:
 
 private:
   ~WorkerListener()
   {
     MOZ_ASSERT(!mListeningForEvents);
   }
 };
 
-NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistrationWorkerThread, ServiceWorkerRegistration)
-NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistrationWorkerThread, ServiceWorkerRegistration)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerRegistrationWorkerThread)
-NS_INTERFACE_MAP_END_INHERITING(ServiceWorkerRegistration)
-
-// Expanded macros since we need special behaviour to release the proxy.
-NS_IMPL_CYCLE_COLLECTION_CLASS(ServiceWorkerRegistrationWorkerThread)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServiceWorkerRegistrationWorkerThread,
-                                                  ServiceWorkerRegistration)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPushManager)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ServiceWorkerRegistrationWorkerThread,
-                                                ServiceWorkerRegistration)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPushManager)
-  tmp->ReleaseListener();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
 ServiceWorkerRegistrationWorkerThread::ServiceWorkerRegistrationWorkerThread(WorkerPrivate* aWorkerPrivate,
                                                                              const ServiceWorkerRegistrationDescriptor& aDescriptor)
-  : ServiceWorkerRegistration(nullptr, aDescriptor)
-  , WorkerHolder("ServiceWorkerRegistrationWorkerThread")
+  : WorkerHolder("ServiceWorkerRegistrationWorkerThread")
+  , mOuter(nullptr)
   , mWorkerPrivate(aWorkerPrivate)
   , mScope(NS_ConvertUTF8toUTF16(aDescriptor.Scope()))
 {
-  InitListener();
 }
 
 ServiceWorkerRegistrationWorkerThread::~ServiceWorkerRegistrationWorkerThread()
 {
+  MOZ_DIAGNOSTIC_ASSERT(!mListener);
+  MOZ_DIAGNOSTIC_ASSERT(!mOuter);
+}
+
+void
+ServiceWorkerRegistrationWorkerThread::SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aReg);
+  MOZ_DIAGNOSTIC_ASSERT(!mOuter);
+  mOuter = aReg;
+  InitListener();
+}
+
+void
+ServiceWorkerRegistrationWorkerThread::ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg)
+{
+  MOZ_DIAGNOSTIC_ASSERT(mOuter);
+  MOZ_DIAGNOSTIC_ASSERT(mOuter == aReg);
   ReleaseListener();
-  MOZ_ASSERT(!mListener);
+  mOuter = nullptr;
 }
 
 already_AddRefed<Promise>
 ServiceWorkerRegistrationWorkerThread::Update(ErrorResult& aRv)
 {
   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(worker);
   worker->AssertIsOnWorkerThread();
@@ -894,17 +890,17 @@ ServiceWorkerRegistrationWorkerThread::U
 void
 ServiceWorkerRegistrationWorkerThread::InitListener()
 {
   MOZ_ASSERT(!mListener);
   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(worker);
   worker->AssertIsOnWorkerThread();
 
-  mListener = new WorkerListener(worker, this);
+  mListener = new WorkerListener(worker, this, mScope);
   if (!HoldWorker(worker, Closing)) {
     mListener = nullptr;
     NS_WARNING("Could not add feature");
     return;
   }
 
   nsCOMPtr<nsIRunnable> r =
     NewRunnableMethod("dom::WorkerListener::StartListeningForEvents",
@@ -965,17 +961,17 @@ public:
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
 
     ServiceWorkerRegistrationWorkerThread* reg = mListener->GetRegistration();
     if (reg) {
-      reg->DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
+      reg->UpdateFound();
     }
     return true;
   }
 };
 
 void
 WorkerListener::UpdateFound()
 {
@@ -1014,18 +1010,20 @@ ServiceWorkerRegistrationWorkerThread::G
                                                         ErrorResult& aRv)
 {
   return Notification::WorkerGet(mWorkerPrivate, aOptions, mScope, aRv);
 }
 
 already_AddRefed<PushManager>
 ServiceWorkerRegistrationWorkerThread::GetPushManager(JSContext* aCx, ErrorResult& aRv)
 {
-  if (!mPushManager) {
-    mPushManager = new PushManager(mScope);
-  }
+  RefPtr<PushManager> ret = new PushManager(mScope);
+  return ret.forget();
+}
 
-  RefPtr<PushManager> ret = mPushManager;
-  return ret.forget();
+void
+ServiceWorkerRegistrationWorkerThread::UpdateFound()
+{
+  mOuter->DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/serviceworkers/ServiceWorkerRegistrationImpl.h
+++ b/dom/serviceworkers/ServiceWorkerRegistrationImpl.h
@@ -18,55 +18,50 @@ namespace dom {
 
 class Promise;
 class PushManager;
 class ServiceWorker;
 
 ////////////////////////////////////////////////////
 // Main Thread implementation
 
-class ServiceWorkerRegistrationMainThread final : public ServiceWorkerRegistration,
-                                                  public ServiceWorkerRegistrationListener
+class ServiceWorkerRegistrationMainThread final : public ServiceWorkerRegistration::Inner
+                                                , public ServiceWorkerRegistrationListener
 {
-  friend nsPIDOMWindowInner;
 public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistrationMainThread,
-                                           ServiceWorkerRegistration)
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerRegistrationMainThread, override)
+
+  explicit ServiceWorkerRegistrationMainThread(const ServiceWorkerRegistrationDescriptor& aDescriptor);
 
-  ServiceWorkerRegistrationMainThread(nsPIDOMWindowInner* aWindow,
-                                      const ServiceWorkerRegistrationDescriptor& aDescriptor);
+  // ServiceWorkerRegistration::Inner
+  void
+  SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
+
+  void
+  ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
 
   already_AddRefed<Promise>
   Update(ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   Unregister(ErrorResult& aRv) override;
 
-  // Partial interface from Notification API.
   already_AddRefed<Promise>
   ShowNotification(JSContext* aCx,
                    const nsAString& aTitle,
                    const NotificationOptions& aOptions,
                    ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   GetNotifications(const GetNotificationOptions& aOptions,
                    ErrorResult& aRv) override;
 
   already_AddRefed<PushManager>
   GetPushManager(JSContext* aCx, ErrorResult& aRv) override;
 
-  // DOMEventTargethelper
-  void DisconnectFromOwner() override
-  {
-    StopListeningForEvents();
-    ServiceWorkerRegistration::DisconnectFromOwner();
-  }
-
   // ServiceWorkerRegistrationListener
   void
   UpdateFound() override;
 
   void
   UpdateState(const ServiceWorkerRegistrationDescriptor& aDescriptor) override;
 
   void
@@ -85,71 +80,77 @@ private:
   ~ServiceWorkerRegistrationMainThread();
 
   void
   StartListeningForEvents();
 
   void
   StopListeningForEvents();
 
+  ServiceWorkerRegistration* mOuter;
   const nsString mScope;
   bool mListeningForEvents;
-
-  RefPtr<PushManager> mPushManager;
 };
 
 ////////////////////////////////////////////////////
 // Worker Thread implementation
 
 class WorkerListener;
 
-class ServiceWorkerRegistrationWorkerThread final : public ServiceWorkerRegistration
+class ServiceWorkerRegistrationWorkerThread final : public ServiceWorkerRegistration::Inner
                                                   , public WorkerHolder
 {
 public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistrationWorkerThread,
-                                           ServiceWorkerRegistration)
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerRegistrationWorkerThread, override)
 
   ServiceWorkerRegistrationWorkerThread(WorkerPrivate* aWorkerPrivate,
                                         const ServiceWorkerRegistrationDescriptor& aDescriptor);
 
+  // ServiceWorkerRegistration::Inner
+  void
+  SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
+
+  void
+  ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
+
   already_AddRefed<Promise>
   Update(ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   Unregister(ErrorResult& aRv) override;
 
-  // Partial interface from Notification API.
   already_AddRefed<Promise>
   ShowNotification(JSContext* aCx,
                    const nsAString& aTitle,
                    const NotificationOptions& aOptions,
                    ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   GetNotifications(const GetNotificationOptions& aOptions,
                    ErrorResult& aRv) override;
 
+  already_AddRefed<PushManager>
+  GetPushManager(JSContext* aCx, ErrorResult& aRv) override;
+
+  // WorkerHolder
   bool
   Notify(WorkerStatus aStatus) override;
 
-  already_AddRefed<PushManager>
-  GetPushManager(JSContext* aCx, ErrorResult& aRv) override;
+  void
+  UpdateFound();
 
 private:
   ~ServiceWorkerRegistrationWorkerThread();
 
   void
   InitListener();
 
   void
   ReleaseListener();
 
+  ServiceWorkerRegistration* mOuter;
   WorkerPrivate* mWorkerPrivate;
   const nsString mScope;
   RefPtr<WorkerListener> mListener;
-
-  RefPtr<PushManager> mPushManager;
 };
 
 } // dom namespace
 } // mozilla namespace