Backed out changeset f03cd54afbc1 (bug 1263304) for causing frequent timeouts in test_has_permissions.html
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 11 Nov 2016 10:48:20 +0100
changeset 352185 b1f4c3608bc067ec1d7fc93731cfcf6cd109bc6b
parent 352184 a10fce0b6fc805631dc3065c513c0bcb60906015
child 352186 f33bcb35609a9c0a5a2173951f99e4ddcff9a536
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1263304
milestone52.0a1
backs outf03cd54afbc1297a7b7dbf0b25a9d76d8b7de806
Backed out changeset f03cd54afbc1 (bug 1263304) for causing frequent timeouts in test_has_permissions.html
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -2,17 +2,16 @@
 /* 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"
@@ -100,16 +99,74 @@ 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
 
@@ -411,122 +468,16 @@ 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,16 +100,17 @@
 #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"
 
@@ -603,25 +604,38 @@ 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.
@@ -671,33 +685,73 @@ public:
     }
 
     Sequence<OwningNonNull<MessagePort>> ports;
     if (!TakeTransferredPortsAsSequence(ports)) {
       return false;
     }
 
     nsCOMPtr<nsIDOMEvent> domEvent;
-    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<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);
+    }
 
     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) {
@@ -2918,16 +2972,18 @@ 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;
@@ -2979,29 +3035,45 @@ 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, 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);
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateContextOptions(
                                     const JS::ContextOptions& aContextOptions)
 {
   AssertIsOnParentThread();
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -247,16 +247,18 @@ 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;
@@ -361,16 +363,23 @@ 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);