Bug 1288618 - Part 6: Avoid unnecessarily allocating a TailDispatcher for XPCOMThreadWrapper. r=bholley
☠☠ backed out by 8b6401bcb115 ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 21 Sep 2016 15:36:09 +1200
changeset 314686 8f67443dccb8f733e152e7fffa07f969444ab2b1
parent 314685 4e7fe69d5f456cc42e4ee65418e2892bf0c9c3bd
child 314687 63a9c689e1d50c981b60ffd6992c6d85b0dfe7b2
push id30732
push usercbook@mozilla.com
push dateWed, 21 Sep 2016 10:04:03 +0000
treeherdermozilla-central@560b2c805bf7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1288618
milestone52.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;