Bug 1288618 - Part 6: Avoid unnecessarily allocating a TailDispatcher for XPCOMThreadWrapper. r=bholley
☠☠ backed out by deb400c9f162 ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 15 Sep 2016 23:17:59 +1200
changeset 355344 fdee8d1538b02a69595f2c715cb9b93e9747c008
parent 355343 ddaa7f107193bb1c9478c2d1838047936e30a827
child 355345 30e2b2eea845c8c2772743c97ac4ceda529aab2d
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1288618
milestone51.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 1288618 - Part 6: Avoid unnecessarily allocating a TailDispatcher for XPCOMThreadWrapper. r=bholley
xpcom/threads/AbstractThread.cpp
xpcom/threads/AbstractThread.h
xpcom/threads/TaskQueue.cpp
--- a/xpcom/threads/AbstractThread.cpp
+++ b/xpcom/threads/AbstractThread.cpp
@@ -89,23 +89,45 @@ public:
 
       nsCOMPtr<nsIRunnable> event = NewRunnableMethod(this, &XPCOMThreadWrapper::FireTailDispatcher);
       nsContentUtils::RunInStableState(event.forget());
     }
 
     return mTailDispatcher.ref();
   }
 
+  virtual bool MightHaveTailTasks() override
+  {
+    return mTailDispatcher.isSome();
+  }
+
   virtual nsIThread* AsXPCOMThread() override { return mTarget; }
 
 private:
   RefPtr<nsIThread> mTarget;
   Maybe<AutoTaskDispatcher> mTailDispatcher;
 };
 
+void
+AbstractThread::TailDispatchTasksFor(AbstractThread* aThread)
+{
+  if (MightHaveTailTasks()) {
+    TailDispatcher().DispatchTasksFor(aThread);
+  }
+}
+
+bool
+AbstractThread::HasTailTasksFor(AbstractThread* aThread)
+{
+  if (!MightHaveTailTasks()) {
+    return false;
+  }
+  return TailDispatcher().HasTasksFor(aThread);
+}
+
 bool
 AbstractThread::RequiresTailDispatch(AbstractThread* aThread) const
 {
   MOZ_ASSERT(aThread);
   // We require tail dispatch if both the source and destination
   // threads support it.
   return SupportsTailDispatch() && aThread->SupportsTailDispatch();
 }
--- a/xpcom/threads/AbstractThread.h
+++ b/xpcom/threads/AbstractThread.h
@@ -61,16 +61,26 @@ public:
 
   // Returns a TaskDispatcher that will dispatch its tasks when the currently-
   // running tasks pops off the stack.
   //
   // May only be called when running within the it is invoked up, and only on
   // threads which support it.
   virtual TaskDispatcher& TailDispatcher() = 0;
 
+  // Returns true if we have tail tasks scheduled, or if this isn't known.
+  // Returns false if we definitely don't have any tail tasks.
+  virtual bool MightHaveTailTasks() { return true; }
+
+  // Helper functions for methods on the tail TasklDispatcher. These check
+  // HasTailTasks to avoid allocating a TailDispatcher if it isn't
+  // needed.
+  void TailDispatchTasksFor(AbstractThread* aThread);
+  bool HasTailTasksFor(AbstractThread* aThread);
+
   // Returns true if this supports the tail dispatcher.
   bool SupportsTailDispatch() const { return mSupportsTailDispatch; }
 
   // Returns true if this thread requires all dispatches originating from
   // aThread go through the tail dispatcher.
   bool RequiresTailDispatch(AbstractThread* aThread) const;
   bool RequiresTailDispatchFromCurrentThread() const;
 
--- a/xpcom/threads/TaskQueue.cpp
+++ b/xpcom/threads/TaskQueue.cpp
@@ -133,48 +133,48 @@ TaskQueue::AwaitIdle()
 }
 
 void
 TaskQueue::AwaitIdleLocked()
 {
   // Make sure there are no tasks for this queue waiting in the caller's tail
   // dispatcher.
   MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
-                !AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
+                !AbstractThread::GetCurrent()->HasTailTasksFor(this));
 
   mQueueMonitor.AssertCurrentThreadOwns();
   MOZ_ASSERT(mIsRunning || mTasks.empty());
   while (mIsRunning) {
     mQueueMonitor.Wait();
   }
 }
 
 void
 TaskQueue::AwaitShutdownAndIdle()
 {
   MOZ_ASSERT(!IsCurrentThreadIn());
   // Make sure there are no tasks for this queue waiting in the caller's tail
   // dispatcher.
   MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
-                !AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
+                !AbstractThread::GetCurrent()->HasTailTasksFor(this));
 
   MonitorAutoLock mon(mQueueMonitor);
   while (!mIsShutdown) {
     mQueueMonitor.Wait();
   }
   AwaitIdleLocked();
 }
 
 RefPtr<ShutdownPromise>
 TaskQueue::BeginShutdown()
 {
   // Dispatch any tasks for this queue waiting in the caller's tail dispatcher,
   // since this is the last opportunity to do so.
   if (AbstractThread* currentThread = AbstractThread::GetCurrent()) {
-    currentThread->TailDispatcher().DispatchTasksFor(this);
+    currentThread->TailDispatchTasksFor(this);
   }
 
   MonitorAutoLock mon(mQueueMonitor);
   mIsShutdown = true;
   RefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
   MaybeResolveShutdown();
   mon.NotifyAll();
   return p;