Bug 966384 - Promises on workers use correct busy count. r=khuey
authorNikhil Marathe <nsm.nikhil@gmail.com>
Mon, 17 Feb 2014 12:24:36 +0530
changeset 169095 b98808ff6c8954cd2ae74e6378f49ac48b1f7a97
parent 169094 ca5cfa58f6a2aaafaa9497f091451b413242d4b3
child 169096 8112ba0e9eb62bd6e4a280828a29b07cd09d679b
push id26230
push usercbook@mozilla.com
push dateMon, 17 Feb 2014 11:48:24 +0000
treeherdermozilla-central@8112ba0e9eb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs966384
milestone30.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 966384 - Promises on workers use correct busy count. r=khuey
dom/promise/Promise.cpp
dom/workers/WorkerRunnable.cpp
dom/workers/WorkerRunnable.h
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -52,21 +52,21 @@ public:
     mPromise->RunTask();
     return NS_OK;
   }
 
 private:
   nsRefPtr<Promise> mPromise;
 };
 
-class WorkerPromiseTask MOZ_FINAL : public WorkerRunnable
+class WorkerPromiseTask MOZ_FINAL : public WorkerSameThreadRunnable
 {
 public:
   WorkerPromiseTask(WorkerPrivate* aWorkerPrivate, Promise* aPromise)
-    : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
+    : WorkerSameThreadRunnable(aWorkerPrivate)
     , mPromise(aPromise)
   {
     MOZ_ASSERT(aPromise);
     MOZ_COUNT_CTOR(WorkerPromiseTask);
   }
 
   ~WorkerPromiseTask()
   {
@@ -156,25 +156,25 @@ public:
 
   NS_IMETHOD Run()
   {
     RunInternal();
     return NS_OK;
   }
 };
 
-class WorkerPromiseResolverTask MOZ_FINAL : public WorkerRunnable,
+class WorkerPromiseResolverTask MOZ_FINAL : public WorkerSameThreadRunnable,
                                             public PromiseResolverMixin
 {
 public:
   WorkerPromiseResolverTask(WorkerPrivate* aWorkerPrivate,
                             Promise* aPromise,
                             JS::Handle<JS::Value> aValue,
                             Promise::PromiseState aState)
-    : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
+    : WorkerSameThreadRunnable(aWorkerPrivate),
       PromiseResolverMixin(aPromise, aValue, aState)
   {}
 
   ~WorkerPromiseResolverTask()
   {}
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
@@ -827,17 +827,17 @@ Promise::AppendCallbacks(PromiseCallback
   if (mState != Pending && !mTaskPending) {
     if (MOZ_LIKELY(NS_IsMainThread())) {
       nsRefPtr<PromiseTask> task = new PromiseTask(this);
       NS_DispatchToCurrentThread(task);
     } else {
       WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
       MOZ_ASSERT(worker);
       nsRefPtr<WorkerPromiseTask> task = new WorkerPromiseTask(worker, this);
-      worker->Dispatch(task);
+      task->Dispatch(worker->GetJSContext());
     }
     mTaskPending = true;
   }
 }
 
 void
 Promise::RunTask()
 {
@@ -1040,17 +1040,17 @@ Promise::RunResolveTask(JS::Handle<JS::V
       nsRefPtr<PromiseResolverTask> task =
         new PromiseResolverTask(this, aValue, aState);
       NS_DispatchToCurrentThread(task);
     } else {
       WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
       MOZ_ASSERT(worker);
       nsRefPtr<WorkerPromiseResolverTask> task =
         new WorkerPromiseResolverTask(worker, this, aValue, aState);
-      worker->Dispatch(task);
+      task->Dispatch(worker->GetJSContext());
     }
     return;
   }
 
   // Promise.all() or Promise.race() implementations will repeatedly call
   // Resolve/RejectInternal rather than using the Maybe... forms. Stop SetState
   // from asserting.
   if (mState != Pending) {
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -2,20 +2,22 @@
 /* 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 "WorkerRunnable.h"
 
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+
+#include "mozilla/DebugOnly.h"
 
 #include "js/RootingAPI.h"
 #include "js/Value.h"
-#include "nsThreadUtils.h"
 
 #include "WorkerPrivate.h"
 
 USING_WORKERS_NAMESPACE
 
 namespace {
 
 const nsIID kWorkerRunnableIID = {
@@ -473,8 +475,48 @@ MainThreadWorkerControlRunnable::PostDis
   AssertIsOnMainThread();
 
   if (aCx && !aDispatchResult) {
     JS_ReportPendingException(aCx);
   }
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable)
+
+bool
+WorkerSameThreadRunnable::PreDispatch(JSContext* aCx,
+                                      WorkerPrivate* aWorkerPrivate)
+{
+  aWorkerPrivate->AssertIsOnWorkerThread();
+  return true;
+}
+
+void
+WorkerSameThreadRunnable::PostDispatch(JSContext* aCx,
+                                       WorkerPrivate* aWorkerPrivate,
+                                       bool aDispatchResult)
+{
+  aWorkerPrivate->AssertIsOnWorkerThread();
+  if (aDispatchResult) {
+    DebugOnly<bool> willIncrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true);
+    // Should never fail since if this thread is still running, so should the
+    // parent and it should be able to process a control runnable.
+    MOZ_ASSERT(willIncrement);
+  }
+}
+
+void
+WorkerSameThreadRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+                                  bool aRunResult)
+{
+  MOZ_ASSERT(aCx);
+  MOZ_ASSERT(aWorkerPrivate);
+
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  DebugOnly<bool> willDecrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false);
+  MOZ_ASSERT(willDecrement);
+
+  if (!aRunResult) {
+    JS_ReportPendingException(aCx);
+  }
+}
+
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -309,11 +309,39 @@ protected:
     return true;
   }
 
   virtual void
   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                bool aDispatchResult) MOZ_OVERRIDE;
 };
 
+// A WorkerRunnable that should be dispatched from the worker to itself for
+// async tasks. This will increment the busy count PostDispatch() (only if
+// dispatch was successful) and decrement it in PostRun().
+//
+// Async tasks will almost always want to use this since
+// a WorkerSameThreadRunnable keeps the Worker from being GCed.
+class WorkerSameThreadRunnable : public WorkerRunnable
+{
+protected:
+  WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
+  : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+  { }
+
+  virtual ~WorkerSameThreadRunnable()
+  { }
+
+  virtual bool
+  PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
+
+  virtual void
+  PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+               bool aDispatchResult) MOZ_OVERRIDE;
+
+  virtual void
+  PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+          bool aRunResult) MOZ_OVERRIDE;
+};
+
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_workerrunnable_h__