Bug 1456466 P2 Make ServiceWorkerRegistration::Inner::Update() use MozPromise and IPC-safe types. r=baku
☠☠ backed out by b2a75639bd93 ☠ ☠
authorBen Kelly <ben@wanderview.com>
Tue, 24 Apr 2018 06:32:14 -0700
changeset 471444 e3a50afee79e2212c1590430a080d7552d3cd491
parent 471443 89ce7df053441fe04350dbdb0100d011fa8ef5e7
child 471445 fd0feb0058fc93361dc94df776a9fea43c0aab82
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1456466
milestone61.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 1456466 P2 Make ServiceWorkerRegistration::Inner::Update() use MozPromise and IPC-safe types. r=baku
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
@@ -193,17 +193,50 @@ ServiceWorkerRegistration::GetUpdateViaC
 
 already_AddRefed<Promise>
 ServiceWorkerRegistration::Update(ErrorResult& aRv)
 {
   if (!mInner) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
-  return mInner->Update(aRv);
+
+  nsIGlobalObject* global = GetParentObject();
+  if (!global) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
+  RefPtr<Promise> outer = Promise::Create(global, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  RefPtr<ServiceWorkerRegistration> self = this;
+
+  mInner->Update(aRv)->Then(
+    global->EventTargetFor(TaskCategory::Other), __func__,
+    [outer, self](const ServiceWorkerRegistrationDescriptor& aDesc) {
+      nsIGlobalObject* global = self->GetParentObject();
+      if (!global) {
+        outer->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+        return;
+      }
+      RefPtr<ServiceWorkerRegistration> ref =
+        global->GetOrCreateServiceWorkerRegistration(aDesc);
+      if (!ref) {
+        outer->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+        return;
+      }
+      outer->MaybeResolve(ref);
+    }, [outer] (ErrorResult&& aRv) {
+      outer->MaybeReject(aRv);
+    });
+
+  return outer.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerRegistration::Unregister(ErrorResult& aRv)
 {
   if (!mInner) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
--- a/dom/serviceworkers/ServiceWorkerRegistration.h
+++ b/dom/serviceworkers/ServiceWorkerRegistration.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_ServiceWorkerRegistration_h
 #define mozilla_dom_ServiceWorkerRegistration_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ServiceWorkerBinding.h"
 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
+#include "mozilla/dom/ServiceWorkerUtils.h"
 
 // Support for Notification API extension.
 #include "mozilla/dom/NotificationBinding.h"
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
@@ -38,17 +39,17 @@ public:
     NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
 
     virtual void
     SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) = 0;
 
     virtual void
     ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) = 0;
 
-    virtual already_AddRefed<Promise>
+    virtual RefPtr<ServiceWorkerRegistrationPromise>
     Update(ErrorResult& aRv) = 0;
 
     virtual already_AddRefed<Promise>
     Unregister(ErrorResult& aRv) = 0;
 
     virtual already_AddRefed<Promise>
     ShowNotification(JSContext* aCx,
                      const nsAString& aTitle,
--- a/dom/serviceworkers/ServiceWorkerRegistrationImpl.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrationImpl.cpp
@@ -38,16 +38,17 @@
 namespace mozilla {
 namespace dom {
 
 ////////////////////////////////////////////////////
 // Main Thread implementation
 
 ServiceWorkerRegistrationMainThread::ServiceWorkerRegistrationMainThread(const ServiceWorkerRegistrationDescriptor& aDescriptor)
   : mOuter(nullptr)
+  , mDescriptor(aDescriptor)
   , mScope(NS_ConvertUTF8toUTF16(aDescriptor.Scope()))
   , mListeningForEvents(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 ServiceWorkerRegistrationMainThread::~ServiceWorkerRegistrationMainThread()
 {
@@ -101,16 +102,17 @@ void
 ServiceWorkerRegistrationMainThread::UpdateFound()
 {
   mOuter->DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
 }
 
 void
 ServiceWorkerRegistrationMainThread::UpdateState(const ServiceWorkerRegistrationDescriptor& aDescriptor)
 {
+  mDescriptor = aDescriptor;
   mOuter->UpdateState(aDescriptor);
 }
 
 void
 ServiceWorkerRegistrationMainThread::RegistrationRemoved()
 {
   // Queue a runnable to clean up the registration.  This is necessary
   // because there may be runnables in the event queue already to
@@ -163,141 +165,71 @@ UpdateInternal(nsIPrincipal* aPrincipal,
     return;
   }
 
   swm->Update(aPrincipal, aScope, aCallback);
 }
 
 class MainThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
 {
-  PromiseWindowProxy mPromise;
+  RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise;
 
   ~MainThreadUpdateCallback()
   { }
 
 public:
-  explicit MainThreadUpdateCallback(nsPIDOMWindowInner* aWindow,
-                                    Promise* aPromise)
-    : mPromise(aWindow, aPromise)
+  MainThreadUpdateCallback()
+    : mPromise(new ServiceWorkerRegistrationPromise::Private(__func__))
+  {
+  }
+
+  void
+  UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override
+  {
+    mPromise->Resolve(aRegistration->Descriptor(), __func__);
+  }
+
+  void
+  UpdateFailed(ErrorResult& aStatus) override
+  {
+    mPromise->Reject(Move(aStatus), __func__);
+  }
+
+  RefPtr<ServiceWorkerRegistrationPromise>
+  Promise() const
+  {
+    return mPromise;
+  }
+};
+
+class WorkerThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
+{
+  RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise;
+
+  ~WorkerThreadUpdateCallback()
+  {
+  }
+
+public:
+  explicit WorkerThreadUpdateCallback(ServiceWorkerRegistrationPromise::Private* aPromise)
+    : mPromise(aPromise)
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   void
   UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override
   {
-    RefPtr<Promise> promise = mPromise.Get();
-    nsCOMPtr<nsPIDOMWindowInner> win = mPromise.GetWindow();
-    if (!promise || !win) {
-      return;
-    }
-
-    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
-      "MainThreadUpdateCallback::UpdateSucceeded",
-      [promise = Move(promise)] () {
-        promise->MaybeResolveWithUndefined();
-      });
-    MOZ_ALWAYS_SUCCEEDS(
-      win->EventTargetFor(TaskCategory::Other)->Dispatch(r.forget()));
+    mPromise->Resolve(aRegistration->Descriptor(), __func__);
   }
 
   void
   UpdateFailed(ErrorResult& aStatus) override
   {
-    if (RefPtr<Promise> promise = mPromise.Get()) {
-      promise->MaybeReject(aStatus);
-    }
-  }
-};
-
-class UpdateResultRunnable final : public WorkerRunnable
-{
-  RefPtr<PromiseWorkerProxy> mPromiseProxy;
-  IPC::Message mSerializedErrorResult;
-
-  ~UpdateResultRunnable()
-  {}
-
-public:
-  UpdateResultRunnable(PromiseWorkerProxy* aPromiseProxy, ErrorResult& aStatus)
-    : WorkerRunnable(aPromiseProxy->GetWorkerPrivate())
-    , mPromiseProxy(aPromiseProxy)
-  {
-    // ErrorResult is not thread safe.  Serialize it for transfer across
-    // threads.
-    IPC::WriteParam(&mSerializedErrorResult, aStatus);
-    aStatus.SuppressException();
-  }
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    // Deserialize the ErrorResult now that we are back in the worker
-    // thread.
-    ErrorResult status;
-    PickleIterator iter = PickleIterator(mSerializedErrorResult);
-    Unused << IPC::ReadParam(&mSerializedErrorResult, &iter, &status);
-
-    Promise* promise = mPromiseProxy->WorkerPromise();
-    if (status.Failed()) {
-      promise->MaybeReject(status);
-    } else {
-      promise->MaybeResolveWithUndefined();
-    }
-    status.SuppressException();
-    mPromiseProxy->CleanUp();
-    return true;
-  }
-};
-
-class WorkerThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
-{
-  RefPtr<PromiseWorkerProxy> mPromiseProxy;
-
-  ~WorkerThreadUpdateCallback()
-  {
-  }
-
-public:
-  explicit WorkerThreadUpdateCallback(PromiseWorkerProxy* aPromiseProxy)
-    : mPromiseProxy(aPromiseProxy)
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-  }
-
-  void
-  UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override
-  {
-    ErrorResult rv(NS_OK);
-    Finish(rv);
-  }
-
-  void
-  UpdateFailed(ErrorResult& aStatus) override
-  {
-    Finish(aStatus);
-  }
-
-  void
-  Finish(ErrorResult& aStatus)
-  {
-    if (!mPromiseProxy) {
-      return;
-    }
-
-    RefPtr<PromiseWorkerProxy> proxy = mPromiseProxy.forget();
-
-    MutexAutoLock lock(proxy->Lock());
-    if (proxy->CleanedUp()) {
-      return;
-    }
-
-    RefPtr<UpdateResultRunnable> r =
-      new UpdateResultRunnable(proxy, aStatus);
-    r->Dispatch();
+    mPromise->Reject(Move(aStatus), __func__);
   }
 };
 
 class SWRUpdateRunnable final : public Runnable
 {
   class TimerCallback final : public nsITimerCallback
   {
     RefPtr<ServiceWorkerPrivate> mPrivate;
@@ -325,52 +257,39 @@ class SWRUpdateRunnable final : public R
     NS_DECL_THREADSAFE_ISUPPORTS
 
   private:
     ~TimerCallback()
     { }
   };
 
 public:
-  explicit SWRUpdateRunnable(PromiseWorkerProxy* aPromiseProxy)
+  explicit SWRUpdateRunnable(const ServiceWorkerDescriptor& aDescriptor)
     : Runnable("dom::SWRUpdateRunnable")
-    , mPromiseProxy(aPromiseProxy)
-    , mDescriptor(aPromiseProxy->GetWorkerPrivate()->GetServiceWorkerDescriptor())
+    , mPromise(new ServiceWorkerRegistrationPromise::Private(__func__))
+    , mDescriptor(aDescriptor)
     , mDelayed(false)
   {
-    MOZ_ASSERT(mPromiseProxy);
-
-    // This runnable is used for update calls originating from a worker thread,
-    // which may be delayed in some cases.
-    MOZ_ASSERT(mPromiseProxy->GetWorkerPrivate()->IsServiceWorker());
-    MOZ_ASSERT(mPromiseProxy->GetWorkerPrivate());
-    mPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
   }
 
   NS_IMETHOD
   Run() override
   {
     MOZ_ASSERT(NS_IsMainThread());
     ErrorResult result;
 
-    nsCOMPtr<nsIPrincipal> principal;
-    // UpdateInternal may try to reject the promise synchronously leading
-    // to a deadlock.
-    {
-      MutexAutoLock lock(mPromiseProxy->Lock());
-      if (mPromiseProxy->CleanedUp()) {
-        return NS_OK;
-      }
-
-      principal = mPromiseProxy->GetWorkerPrivate()->GetPrincipal();
+    nsCOMPtr<nsIPrincipal> principal = mDescriptor.GetPrincipal();
+    if (NS_WARN_IF(!principal)) {
+      mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
+      return NS_OK;
     }
-    MOZ_ASSERT(principal);
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     if (NS_WARN_IF(!swm)) {
+      mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
       return NS_OK;
     }
 
     // This will delay update jobs originating from a service worker thread.
     // We don't currently handle ServiceWorkerRegistration.update() from other
     // worker types. Also, we assume this registration matches self.registration
     // on the service worker global. This is ok for now because service worker globals
     // are the only worker contexts where we expose ServiceWorkerRegistration.
@@ -406,28 +325,32 @@ public:
         timer->Cancel();
         return NS_OK;
       }
 
       return NS_OK;
     }
 
     RefPtr<WorkerThreadUpdateCallback> cb =
-      new WorkerThreadUpdateCallback(mPromiseProxy);
+      new WorkerThreadUpdateCallback(mPromise);
     UpdateInternal(principal, mDescriptor.Scope(), cb);
+
     return NS_OK;
   }
 
+  RefPtr<ServiceWorkerRegistrationPromise>
+  Promise() const
+  {
+    return mPromise;
+  }
+
 private:
-  ~SWRUpdateRunnable()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-  }
+  ~SWRUpdateRunnable() = default;
 
-  RefPtr<PromiseWorkerProxy> mPromiseProxy;
+  RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise;
   const ServiceWorkerDescriptor mDescriptor;
   bool mDelayed;
 };
 
 NS_IMPL_ISUPPORTS(SWRUpdateRunnable::TimerCallback, nsITimerCallback)
 
 class UnregisterCallback final : public nsIServiceWorkerUnregisterCallback
 {
@@ -616,41 +539,32 @@ public:
       cb->UnregisterFailed();
     }
 
     return NS_OK;
   }
 };
 } // namespace
 
-already_AddRefed<Promise>
+RefPtr<ServiceWorkerRegistrationPromise>
 ServiceWorkerRegistrationMainThread::Update(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(mOuter);
 
-  nsCOMPtr<nsIGlobalObject> go = mOuter->GetParentObject();
-  if (!go) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
+  nsCOMPtr<nsIPrincipal> principal = mDescriptor.GetPrincipal();
+  if (!principal) {
+    return ServiceWorkerRegistrationPromise::CreateAndReject(
+      NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
   }
 
-  RefPtr<Promise> promise = Promise::Create(go, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
+  RefPtr<MainThreadUpdateCallback> cb = new MainThreadUpdateCallback();
+  UpdateInternal(principal, NS_ConvertUTF16toUTF8(mScope), cb);
 
-  nsCOMPtr<nsIDocument> doc = mOuter->GetOwner()->GetExtantDoc();
-  MOZ_ASSERT(doc);
-
-  RefPtr<MainThreadUpdateCallback> cb =
-    new MainThreadUpdateCallback(mOuter->GetOwner(), promise);
-  UpdateInternal(doc->NodePrincipal(), NS_ConvertUTF16toUTF8(mScope), cb);
-
-  return promise.forget();
+  return cb->Promise();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerRegistrationMainThread::Unregister(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(mOuter);
 
@@ -885,16 +799,17 @@ private:
   ~WorkerListener()
   {
     MOZ_ASSERT(!mListeningForEvents);
   }
 };
 
 ServiceWorkerRegistrationWorkerThread::ServiceWorkerRegistrationWorkerThread(const ServiceWorkerRegistrationDescriptor& aDescriptor)
   : mOuter(nullptr)
+  , mDescriptor(aDescriptor)
   , mScope(NS_ConvertUTF8toUTF16(aDescriptor.Scope()))
 {
 }
 
 ServiceWorkerRegistrationWorkerThread::~ServiceWorkerRegistrationWorkerThread()
 {
   MOZ_DIAGNOSTIC_ASSERT(!mListener);
   MOZ_DIAGNOSTIC_ASSERT(!mOuter);
@@ -923,46 +838,66 @@ ServiceWorkerRegistrationWorkerThread::S
 void
 ServiceWorkerRegistrationWorkerThread::ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg)
 {
   MOZ_ASSERT_IF(mOuter, mOuter == aReg);
   ReleaseListener();
   mOuter = nullptr;
 }
 
-already_AddRefed<Promise>
+RefPtr<ServiceWorkerRegistrationPromise>
 ServiceWorkerRegistrationWorkerThread::Update(ErrorResult& aRv)
 {
-  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
-  MOZ_ASSERT(worker);
-  worker->AssertIsOnWorkerThread();
+  if (NS_WARN_IF(!mWorkerRef->GetPrivate())) {
+    return ServiceWorkerRegistrationPromise::CreateAndReject(
+      NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
+  }
 
-  RefPtr<Promise> promise = Promise::Create(worker->GlobalScope(), aRv);
-  if (aRv.Failed()) {
-    return nullptr;
+  RefPtr<StrongWorkerRef> workerRef =
+    StrongWorkerRef::Create(mWorkerRef->GetPrivate(),
+                            "ServiceWorkerRegistration::Update");
+  if (NS_WARN_IF(!workerRef)) {
+    return ServiceWorkerRegistrationPromise::CreateAndReject(
+      NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
   }
 
   // Avoid infinite update loops by ignoring update() calls during top
   // level script evaluation.  See:
   // https://github.com/slightlyoff/ServiceWorker/issues/800
-  if (worker->LoadScriptAsPartOfLoadingServiceWorkerScript()) {
-    promise->MaybeResolveWithUndefined();
-    return promise.forget();
+  if (workerRef->Private()->LoadScriptAsPartOfLoadingServiceWorkerScript()) {
+    return ServiceWorkerRegistrationPromise::CreateAndResolve(mDescriptor,
+                                                              __func__);
+  }
+
+  // Eventually we need to support all workers, but for right now this
+  // code assumes we're on a service worker global as self.registration.
+  if (NS_WARN_IF(!workerRef->Private()->IsServiceWorker())) {
+    return ServiceWorkerRegistrationPromise::CreateAndReject(
+      NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
   }
 
-  RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise);
-  if (!proxy) {
-    aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
-    return nullptr;
+  RefPtr<SWRUpdateRunnable> r =
+    new SWRUpdateRunnable(workerRef->Private()->GetServiceWorkerDescriptor());
+  nsresult rv = workerRef->Private()->DispatchToMainThread(r);
+  if (NS_FAILED(rv)) {
+    return ServiceWorkerRegistrationPromise::CreateAndReject(
+      NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
   }
 
-  RefPtr<SWRUpdateRunnable> r = new SWRUpdateRunnable(proxy);
-  MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
+  RefPtr<ServiceWorkerRegistrationPromise::Private> outer =
+    new ServiceWorkerRegistrationPromise::Private(__func__);
 
-  return promise.forget();
+  r->Promise()->Then(workerRef->Private()->HybridEventTarget(), __func__,
+    [workerRef, outer] (const ServiceWorkerRegistrationDescriptor& aDesc) {
+      outer->Resolve(aDesc, __func__);
+    }, [workerRef, outer] (ErrorResult&& aRv) {
+      outer->Reject(Move(aRv), __func__);
+    });
+
+  return outer.forget();
 }
 
 already_AddRefed<Promise>
 ServiceWorkerRegistrationWorkerThread::Unregister(ErrorResult& aRv)
 {
   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(worker);
   worker->AssertIsOnWorkerThread();
--- a/dom/serviceworkers/ServiceWorkerRegistrationImpl.h
+++ b/dom/serviceworkers/ServiceWorkerRegistrationImpl.h
@@ -37,17 +37,17 @@ public:
 
   // ServiceWorkerRegistration::Inner
   void
   SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
 
   void
   ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
 
-  already_AddRefed<Promise>
+  RefPtr<ServiceWorkerRegistrationPromise>
   Update(ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   Unregister(ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   ShowNotification(JSContext* aCx,
                    const nsAString& aTitle,
@@ -88,16 +88,17 @@ private:
 
   void
   StopListeningForEvents();
 
   void
   RegistrationRemovedInternal();
 
   ServiceWorkerRegistration* mOuter;
+  ServiceWorkerRegistrationDescriptor mDescriptor;
   const nsString mScope;
   bool mListeningForEvents;
 };
 
 ////////////////////////////////////////////////////
 // Worker Thread implementation
 
 class WorkerListener;
@@ -116,17 +117,17 @@ public:
 
   // ServiceWorkerRegistration::Inner
   void
   SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
 
   void
   ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) override;
 
-  already_AddRefed<Promise>
+  RefPtr<ServiceWorkerRegistrationPromise>
   Update(ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   Unregister(ErrorResult& aRv) override;
 
   already_AddRefed<Promise>
   ShowNotification(JSContext* aCx,
                    const nsAString& aTitle,
@@ -152,16 +153,17 @@ private:
   void
   ReleaseListener();
 
   // This can be called only by WorkerListener.
   WorkerPrivate*
   GetWorkerPrivate(const MutexAutoLock& aProofOfLock);
 
   ServiceWorkerRegistration* mOuter;
+  const ServiceWorkerRegistrationDescriptor mDescriptor;
   const nsString mScope;
   RefPtr<WorkerListener> mListener;
   RefPtr<WeakWorkerRef> mWorkerRef;
 };
 
 } // dom namespace
 } // mozilla namespace