Bug 1462772 P3 Make ServiceWorker binding objects get or create a handle to their associated registration. r=mrbkap
authorBen Kelly <ben@wanderview.com>
Mon, 02 Jul 2018 07:44:18 -0700
changeset 424736 f35e21f7239e7b9ff9c01ed76a3a1a2acc84d17c
parent 424735 5a025ad59747e1d41cdd533d92fa7bce5dabd3c6
child 424737 2ba0b36ac85d6d88d4185709a00dd1335bd92d96
push id34223
push useraiakab@mozilla.com
push dateTue, 03 Jul 2018 08:56:10 +0000
treeherdermozilla-central@a0e47ebc4c06 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1462772
milestone63.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 1462772 P3 Make ServiceWorker binding objects get or create a handle to their associated registration. r=mrbkap
dom/serviceworkers/ServiceWorker.cpp
dom/serviceworkers/ServiceWorker.h
dom/serviceworkers/ServiceWorkerImpl.cpp
dom/serviceworkers/ServiceWorkerImpl.h
--- a/dom/serviceworkers/ServiceWorker.cpp
+++ b/dom/serviceworkers/ServiceWorker.cpp
@@ -58,17 +58,17 @@ ServiceWorker::Create(nsIGlobalObject* a
     return ref.forget();
   }
 
   RefPtr<ServiceWorkerInfo> info = reg->GetByDescriptor(aDescriptor);
   if (!info) {
     return ref.forget();
   }
 
-  RefPtr<ServiceWorker::Inner> inner = new ServiceWorkerImpl(info);
+  RefPtr<ServiceWorker::Inner> inner = new ServiceWorkerImpl(info, reg);
   ref = new ServiceWorker(aOwner, aDescriptor, inner);
   return ref.forget();
 }
 
 ServiceWorker::ServiceWorker(nsIGlobalObject* aGlobal,
                              const ServiceWorkerDescriptor& aDescriptor,
                              ServiceWorker::Inner* aInner)
   : DOMEventTargetHelper(aGlobal)
@@ -81,24 +81,53 @@ ServiceWorker::ServiceWorker(nsIGlobalOb
 
   KeepAliveIfHasListenersFor(NS_LITERAL_STRING("statechange"));
 
   // The error event handler is required by the spec currently, but is not used
   // anywhere.  Don't keep the object alive in that case.
 
   // This will update our state too.
   mInner->AddServiceWorker(this);
+
+  // Attempt to get an existing binding object for the registration
+  // associated with this ServiceWorker.
+  RefPtr<ServiceWorkerRegistration> reg = aGlobal->GetServiceWorkerRegistration(
+    ServiceWorkerRegistrationDescriptor(mDescriptor.RegistrationId(),
+                                        mDescriptor.PrincipalInfo(),
+                                        mDescriptor.Scope(),
+                                        ServiceWorkerUpdateViaCache::Imports));
+  if (reg) {
+    MaybeAttachToRegistration(reg);
+  } else {
+    RefPtr<ServiceWorker> self = this;
+
+    mInner->GetRegistration(
+      [self = std::move(self)] (const ServiceWorkerRegistrationDescriptor& aDescriptor) {
+        nsIGlobalObject* global = self->GetParentObject();
+        NS_ENSURE_TRUE_VOID(global);
+        RefPtr<ServiceWorkerRegistration> reg =
+          global->GetOrCreateServiceWorkerRegistration(aDescriptor);
+        self->MaybeAttachToRegistration(reg);
+      }, [] (ErrorResult& aRv) {
+        // do nothing
+        aRv.SuppressException();
+      });
+  }
 }
 
 ServiceWorker::~ServiceWorker()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mInner->RemoveServiceWorker(this);
 }
 
+NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorker,
+                                   DOMEventTargetHelper,
+                                   mRegistration);
+
 NS_IMPL_ADDREF_INHERITED(ServiceWorker, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(ServiceWorker, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorker)
   NS_INTERFACE_MAP_ENTRY(ServiceWorker)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 JSObject*
@@ -196,10 +225,19 @@ ServiceWorker::Descriptor() const
 }
 
 void
 ServiceWorker::DisconnectFromOwner()
 {
   DOMEventTargetHelper::DisconnectFromOwner();
 }
 
+void
+ServiceWorker::MaybeAttachToRegistration(ServiceWorkerRegistration* aRegistration)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aRegistration);
+  MOZ_DIAGNOSTIC_ASSERT(!mRegistration);
+
+  mRegistration = aRegistration;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/serviceworkers/ServiceWorker.h
+++ b/dom/serviceworkers/ServiceWorker.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_serviceworker_h__
 #define mozilla_dom_serviceworker_h__
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ServiceWorkerDescriptor.h"
+#include "mozilla/dom/ServiceWorkerUtils.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 class nsIGlobalObject;
 
 namespace mozilla {
@@ -50,26 +51,33 @@ public:
     virtual void
     AddServiceWorker(ServiceWorker* aWorker) = 0;
 
     // This is called when the DOM ServiceWorker object is
     // destroyed and drops its ref to the Inner object.
     virtual void
     RemoveServiceWorker(ServiceWorker* aWorker) = 0;
 
+    // Get the associated registration for this ServiceWorker.  The success
+    // callback should always be called asynchronously.
+    virtual void
+    GetRegistration(ServiceWorkerRegistrationCallback&& aSuccessCB,
+                    ServiceWorkerFailureCallback&& aFailureCB) = 0;
+
     virtual void
     PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
                 const ClientInfo& aClientInfo,
                 const ClientState& aClientState) = 0;
 
     NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
   };
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_SERVICEWORKER_IID)
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorker, DOMEventTargetHelper)
 
   IMPL_EVENT_HANDLER(statechange)
   IMPL_EVENT_HANDLER(error)
 
   static already_AddRefed<ServiceWorker>
   Create(nsIGlobalObject* aOwner, const ServiceWorkerDescriptor& aDescriptor);
 
   virtual JSObject*
@@ -97,19 +105,23 @@ public:
 private:
   ServiceWorker(nsIGlobalObject* aWindow,
                 const ServiceWorkerDescriptor& aDescriptor,
                 Inner* aInner);
 
   // This class is reference-counted and will be destroyed from Release().
   ~ServiceWorker();
 
+  void
+  MaybeAttachToRegistration(ServiceWorkerRegistration* aRegistration);
+
   ServiceWorkerDescriptor mDescriptor;
 
   RefPtr<Inner> mInner;
+  RefPtr<ServiceWorkerRegistration> mRegistration;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(ServiceWorker, NS_DOM_SERVICEWORKER_IID)
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_serviceworker_h__
--- a/dom/serviceworkers/ServiceWorkerImpl.cpp
+++ b/dom/serviceworkers/ServiceWorkerImpl.cpp
@@ -32,16 +32,52 @@ void
 ServiceWorkerImpl::RemoveServiceWorker(ServiceWorker* aWorker)
 {
   MOZ_DIAGNOSTIC_ASSERT(mOuter);
   MOZ_DIAGNOSTIC_ASSERT(mOuter == aWorker);
   mOuter = nullptr;
 }
 
 void
+ServiceWorkerImpl::GetRegistration(ServiceWorkerRegistrationCallback&& aSuccessCB,
+                                   ServiceWorkerFailureCallback&& aFailureCB)
+{
+  // While we could immediate call success with our registration descriptor
+  // we instead queue a runnable to do this.  This ensures that GetRegistration()
+  // is always async to match how the IPC implementation will work.  It also
+  // ensure that if any events are triggered from providing the registration
+  // that they are fired from a runnable on the correct global's event target.
+
+  if (!mOuter) {
+    aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
+    return;
+  }
+
+  nsIGlobalObject* global = mOuter->GetParentObject();
+  if (!global) {
+    aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
+    return;
+  }
+
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+    "ServiceWorkerImpl::GetRegistration",
+    [reg = mReg, successCB = std::move(aSuccessCB)] () mutable {
+      successCB(reg->Descriptor());
+    });
+
+  nsresult rv =
+    global->EventTargetFor(TaskCategory::Other)->Dispatch(r.forget(),
+                                                          NS_DISPATCH_NORMAL);
+  if (NS_FAILED(rv)) {
+    aFailureCB(CopyableErrorResult(rv));
+    return;
+  }
+}
+
+void
 ServiceWorkerImpl::PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
                                const ClientInfo& aClientInfo,
                                const ClientState& aClientState)
 {
   mInfo->PostMessage(std::move(aData), aClientInfo, aClientState);
 }
 
 void
@@ -49,17 +85,20 @@ ServiceWorkerImpl::SetState(ServiceWorke
 {
   if (!mOuter) {
     return;
   }
   mOuter->SetState(aState);
 }
 
 
-ServiceWorkerImpl::ServiceWorkerImpl(ServiceWorkerInfo* aInfo)
+ServiceWorkerImpl::ServiceWorkerImpl(ServiceWorkerInfo* aInfo,
+                                     ServiceWorkerRegistrationInfo* aReg)
   : mInfo(aInfo)
+  , mReg(aReg)
   , mOuter(nullptr)
 {
   MOZ_DIAGNOSTIC_ASSERT(mInfo);
+  MOZ_DIAGNOSTIC_ASSERT(mReg);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/serviceworkers/ServiceWorkerImpl.h
+++ b/dom/serviceworkers/ServiceWorkerImpl.h
@@ -9,43 +9,50 @@
 
 #include "ServiceWorker.h"
 #include "ServiceWorkerInfo.h"
 
 namespace mozilla {
 namespace dom {
 
 class ServiceWorkerInfo;
+class ServiceWorkerRegistrationInfo;
 
 class ServiceWorkerImpl final : public ServiceWorker::Inner
                               , public ServiceWorkerInfo::Listener
 {
   RefPtr<ServiceWorkerInfo> mInfo;
+  RefPtr<ServiceWorkerRegistrationInfo> mReg;
   ServiceWorker* mOuter;
 
   ~ServiceWorkerImpl();
 
   // ServiceWorker::Inner interface
   void
   AddServiceWorker(ServiceWorker* aWorker) override;
 
   void
   RemoveServiceWorker(ServiceWorker* aWorker) override;
 
   void
+  GetRegistration(ServiceWorkerRegistrationCallback&& aSuccessCB,
+                  ServiceWorkerFailureCallback&& aFailureCB) override;
+
+  void
   PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
               const ClientInfo& aClientInfo,
               const ClientState& aClientState) override;
 
   // ServiceWorkerInfo::Listener interface
   void
   SetState(ServiceWorkerState aState) override;
 
 public:
-  explicit ServiceWorkerImpl(ServiceWorkerInfo* aInfo);
+  ServiceWorkerImpl(ServiceWorkerInfo* aInfo,
+                    ServiceWorkerRegistrationInfo* aReg);
 
   NS_INLINE_DECL_REFCOUNTING(ServiceWorkerImpl, override);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ServiceWorkerImpl_h