Bug 1263304 - Move Service Worker MessageEvent dispatching code to ServiceWorkerPrivate. r=bkelly
authorCatalin Badea <catalin.badea392@gmail.com>
Mon, 21 Nov 2016 02:14:53 +0000
changeset 368541 85a6e5e89b42137920fba26206fe03ae5dc0f2d9
parent 368540 f8cd3227cbfe159128bd5a288f7df248c340f457
child 368542 509e98eec0cebef7fad5bbdd736ea281cef47d49
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly
bugs1263304
milestone53.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 1263304 - Move Service Worker MessageEvent dispatching code to ServiceWorkerPrivate. r=bkelly This refactoring makes it easier to modify the behaviour of lifetime extensions by having a single call path for all extendable events.
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -2,16 +2,17 @@
 /* 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 "ServiceWorkerPrivate.h"
 
 #include "ServiceWorkerManager.h"
+#include "ServiceWorkerWindowClient.h"
 #include "nsContentUtils.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPushErrorReporter.h"
 #include "nsISupportsImpl.h"
 #include "nsIUploadChannel2.h"
 #include "nsNetUtil.h"
@@ -99,74 +100,16 @@ ServiceWorkerPrivate::~ServiceWorkerPriv
   MOZ_ASSERT(!mInfo);
   MOZ_ASSERT(mSupportsArray.IsEmpty());
 
   mIdleWorkerTimer->Cancel();
 }
 
 namespace {
 
-class MessageWaitUntilHandler final : public PromiseNativeHandler
-{
- nsMainThreadPtrHandle<nsISupports> mKeepAliveToken;
-
-  ~MessageWaitUntilHandler()
-  {
-  }
-
-public:
-  explicit MessageWaitUntilHandler(const nsMainThreadPtrHandle<nsISupports>& aKeepAliveToken)
-    : mKeepAliveToken(aKeepAliveToken)
-  {
-    MOZ_ASSERT(mKeepAliveToken);
-  }
-
-  void
-  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
-  {
-    mKeepAliveToken = nullptr;
-  }
-
-  void
-  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
-  {
-    mKeepAliveToken = nullptr;
-  }
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-};
-
-NS_IMPL_ISUPPORTS0(MessageWaitUntilHandler)
-
-} // anonymous namespace
-
-nsresult
-ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
-                                       JS::Handle<JS::Value> aMessage,
-                                       const Optional<Sequence<JS::Value>>& aTransferable,
-                                       UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
-{
-  ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent, nullptr));
-  if (NS_WARN_IF(rv.Failed())) {
-    return rv.StealNSResult();
-  }
-
-  nsMainThreadPtrHandle<nsISupports> token(
-    new nsMainThreadPtrHolder<nsISupports>(CreateEventKeepAliveToken()));
-
-  RefPtr<PromiseNativeHandler> handler = new MessageWaitUntilHandler(token);
-
-  mWorkerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
-                                             Move(aClientInfo), handler,
-                                             rv);
-  return rv.StealNSResult();
-}
-
-namespace {
-
 class CheckScriptEvaluationWithCallback final : public WorkerRunnable
 {
   nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
   RefPtr<LifeCycleEventCallback> mCallback;
 #ifdef DEBUG
   bool mDone;
 #endif
 
@@ -468,16 +411,122 @@ public:
 
     KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
                                                waitUntilPromise);
 
     return true;
   }
 };
 
+class SendMesssageEventRunnable final : public ExtendableEventWorkerRunnable
+                                      , public StructuredCloneHolder
+{
+  UniquePtr<ServiceWorkerClientInfo> mEventSource;
+
+public:
+  SendMesssageEventRunnable(WorkerPrivate*  aWorkerPrivate,
+                            KeepAliveToken* aKeepAliveToken,
+                            UniquePtr<ServiceWorkerClientInfo>&& aEventSource)
+    : ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
+    , StructuredCloneHolder(CloningSupported, TransferringSupported,
+                            StructuredCloneScope::SameProcessDifferentThread)
+    , mEventSource(Move(aEventSource))
+  {
+    AssertIsOnMainThread();
+    MOZ_ASSERT(mEventSource);
+  }
+
+  bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    JS::Rooted<JS::Value> messageData(aCx);
+    nsCOMPtr<nsIGlobalObject> sgo = aWorkerPrivate->GlobalScope();
+    ErrorResult rv;
+    Read(sgo, aCx, &messageData, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return true;
+    }
+
+    Sequence<OwningNonNull<MessagePort>> ports;
+    if (!TakeTransferredPortsAsSequence(ports)) {
+      return true;
+    }
+
+    RefPtr<ServiceWorkerClient> client = new ServiceWorkerWindowClient(sgo,
+                                                                       *mEventSource);
+    RootedDictionary<ExtendableMessageEventInit> init(aCx);
+
+    init.mBubbles = false;
+    init.mCancelable = false;
+
+    init.mData = messageData;
+    init.mPorts = ports;
+    init.mSource.SetValue().SetAsClient() = client;
+
+    RefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
+    RefPtr<ExtendableMessageEvent> extendableEvent =
+      ExtendableMessageEvent::Constructor(target, NS_LITERAL_STRING("message"),
+                                          init, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      rv.SuppressException();
+      return false;
+    }
+
+    extendableEvent->SetTrusted(true);
+
+    return DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
+                                                extendableEvent, nullptr);
+  }
+};
+
+} // anonymous namespace
+
+nsresult
+ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
+                                       JS::Handle<JS::Value> aMessage,
+                                       const Optional<Sequence<JS::Value>>& aTransferable,
+                                       UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
+{
+  AssertIsOnMainThread();
+
+  ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent, nullptr));
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+
+  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedHandleValue);
+  if (aTransferable.WasPassed()) {
+    const Sequence<JS::Value>& value = aTransferable.Value();
+    JS::HandleValueArray elements =
+      JS::HandleValueArray::fromMarkedLocation(value.Length(), value.Elements());
+
+    JSObject* array = JS_NewArrayObject(aCx, elements);
+    if (!array) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    transferable.setObject(*array);
+  }
+  RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
+  RefPtr<SendMesssageEventRunnable> runnable =
+    new SendMesssageEventRunnable(mWorkerPrivate, token, Move(aClientInfo));
+
+  runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+
+  if (!runnable->Dispatch()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+namespace {
+
 // Handle functional event
 // 9.9.7 If the time difference in seconds calculated by the current time minus
 // registration's last update check time is greater than 86400, invoke Soft Update
 // algorithm.
 class ExtendableFunctionalEventWorkerRunnable : public ExtendableEventWorkerRunnable
 {
 protected:
   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -100,17 +100,16 @@
 #endif
 
 #include "Navigator.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "ServiceWorkerEvents.h"
 #include "ServiceWorkerManager.h"
-#include "ServiceWorkerWindowClient.h"
 #include "SharedWorker.h"
 #include "WorkerDebuggerManager.h"
 #include "WorkerHolder.h"
 #include "WorkerNavigator.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 #include "WorkerThread.h"
 
@@ -604,38 +603,25 @@ private:
 
     return true;
   }
 };
 
 class MessageEventRunnable final : public WorkerRunnable
                                  , public StructuredCloneHolder
 {
-  // This is only used for messages dispatched to a service worker.
-  UniquePtr<ServiceWorkerClientInfo> mEventSource;
-
-  RefPtr<PromiseNativeHandler> mHandler;
-
 public:
   MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
                        TargetAndBusyBehavior aBehavior)
   : WorkerRunnable(aWorkerPrivate, aBehavior)
   , StructuredCloneHolder(CloningSupported, TransferringSupported,
                           StructuredCloneScope::SameProcessDifferentThread)
   {
   }
 
-  void
-  SetServiceWorkerData(UniquePtr<ServiceWorkerClientInfo>&& aSource,
-                       PromiseNativeHandler* aHandler)
-  {
-    mEventSource = Move(aSource);
-    mHandler = aHandler;
-  }
-
   bool
   DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                    DOMEventTargetHelper* aTarget, bool aIsMainThread)
   {
     nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(aTarget->GetParentObject());
 
     // For some workers without window, parent is null and we try to find it
     // from the JS Context.
@@ -685,73 +671,33 @@ public:
     }
 
     Sequence<OwningNonNull<MessagePort>> ports;
     if (!TakeTransferredPortsAsSequence(ports)) {
       return false;
     }
 
     nsCOMPtr<nsIDOMEvent> domEvent;
-    RefPtr<ExtendableMessageEvent> extendableEvent;
-    // For messages dispatched to service worker, use ExtendableMessageEvent
-    // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#extendablemessage-event-section
-    if (mEventSource) {
-      RefPtr<ServiceWorkerClient> client =
-        new ServiceWorkerWindowClient(aTarget, *mEventSource);
-
-      RootedDictionary<ExtendableMessageEventInit> init(aCx);
-
-      init.mBubbles = false;
-      init.mCancelable = false;
-
-      init.mData = messageData;
-      init.mPorts = ports;
-      init.mSource.SetValue().SetAsClient() = client;
-
-      ErrorResult rv;
-      extendableEvent = ExtendableMessageEvent::Constructor(
-        aTarget, NS_LITERAL_STRING("message"), init, rv);
-      if (NS_WARN_IF(rv.Failed())) {
-        rv.SuppressException();
-        return false;
-      }
-
-      domEvent = do_QueryObject(extendableEvent);
-    } else {
-      RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
-      event->InitMessageEvent(nullptr,
-                              NS_LITERAL_STRING("message"),
-                              false /* non-bubbling */,
-                              false /* cancelable */,
-                              messageData,
-                              EmptyString(),
-                              EmptyString(),
-                              nullptr,
-                              ports);
-      domEvent = do_QueryObject(event);
-    }
+    RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
+    event->InitMessageEvent(nullptr,
+                            NS_LITERAL_STRING("message"),
+                            false /* non-bubbling */,
+                            false /* cancelable */,
+                            messageData,
+                            EmptyString(),
+                            EmptyString(),
+                            nullptr,
+                            ports);
+    domEvent = do_QueryObject(event);
 
     domEvent->SetTrusted(true);
 
     nsEventStatus dummy = nsEventStatus_eIgnore;
     aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
 
-    if (extendableEvent && mHandler) {
-      RefPtr<Promise> waitUntilPromise = extendableEvent->GetPromise();
-      if (!waitUntilPromise) {
-        waitUntilPromise = Promise::Resolve(parent, aCx,
-                                            JS::UndefinedHandleValue, rv);
-        MOZ_RELEASE_ASSERT(!rv.Failed());
-      }
-
-      MOZ_ASSERT(waitUntilPromise);
-
-      waitUntilPromise->AppendNativeHandler(mHandler);
-    }
-
     return true;
   }
 
 private:
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     if (mBehavior == ParentThreadUnchangedBusyCount) {
@@ -2972,18 +2918,16 @@ WorkerPrivateParent<Derived>::ForgetMain
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::PostMessageInternal(
                                             JSContext* aCx,
                                             JS::Handle<JS::Value> aMessage,
                                             const Optional<Sequence<JS::Value>>& aTransferable,
-                                            UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
-                                            PromiseNativeHandler* aHandler,
                                             ErrorResult& aRv)
 {
   AssertIsOnParentThread();
 
   {
     MutexAutoLock lock(mMutex);
     if (mParentStatus > Running) {
       return;
@@ -3035,45 +2979,29 @@ WorkerPrivateParent<Derived>::PostMessag
     timelines->AddMarkerForAllObservedDocShells(start);
     timelines->AddMarkerForAllObservedDocShells(end);
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  runnable->SetServiceWorkerData(Move(aClientInfo), aHandler);
-
   if (!runnable->Dispatch()) {
     aRv.Throw(NS_ERROR_FAILURE);
   }
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::PostMessage(
                              JSContext* aCx, JS::Handle<JS::Value> aMessage,
                              const Optional<Sequence<JS::Value>>& aTransferable,
                              ErrorResult& aRv)
 {
-  PostMessageInternal(aCx, aMessage, aTransferable, nullptr, nullptr, aRv);
-}
-
-template <class Derived>
-void
-WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
-                             JSContext* aCx, JS::Handle<JS::Value> aMessage,
-                             const Optional<Sequence<JS::Value>>& aTransferable,
-                             UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
-                             PromiseNativeHandler* aHandler,
-                             ErrorResult& aRv)
-{
-  AssertIsOnMainThread();
-  PostMessageInternal(aCx, aMessage, aTransferable, Move(aClientInfo),
-                      aHandler, aRv);
+  PostMessageInternal(aCx, aMessage, aTransferable, aRv);
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateContextOptions(
                                     const JS::ContextOptions& aContextOptions)
 {
   AssertIsOnParentThread();
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -247,18 +247,16 @@ private:
   TerminatePrivate()
   {
     return NotifyPrivate(Terminating);
   }
 
   void
   PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                       const Optional<Sequence<JS::Value>>& aTransferable,
-                      UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
-                      PromiseNativeHandler* aHandler,
                       ErrorResult& aRv);
 
   nsresult
   DispatchPrivate(already_AddRefed<WorkerRunnable> aRunnable, nsIEventTarget* aSyncLoopTarget);
 
 public:
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -363,23 +361,16 @@ public:
   ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
 
   void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Optional<Sequence<JS::Value>>& aTransferable,
               ErrorResult& aRv);
 
   void
-  PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage,
-                             const Optional<Sequence<JS::Value>>& aTransferable,
-                             UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
-                             PromiseNativeHandler* aHandler,
-                             ErrorResult& aRv);
-
-  void
   UpdateContextOptions(const JS::ContextOptions& aContextOptions);
 
   void
   UpdateLanguages(const nsTArray<nsString>& aLanguages);
 
   void
   UpdatePreference(WorkerPreference aPref, bool aValue);