Bug 1314833 - Part 1.2: Define AbstractThreadFor(TaskCategory aCategory) in Dispatcher and DispatcherTrait. r=billm
authorBevis Tseng <btseng@mozilla.com>
Thu, 01 Dec 2016 18:33:05 +0800
changeset 375616 1cf74b47953add5094f559f37766b5e99dfb32a7
parent 375615 8ab1b5ce5bbc6c1fea58d011e94fae39a2cd6cb5
child 375617 0a5d3ec02dcd355cf83eb4b717e8ef2b687f7d0b
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)
reviewersbillm
bugs1314833
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 1314833 - Part 1.2: Define AbstractThreadFor(TaskCategory aCategory) in Dispatcher and DispatcherTrait. r=billm MozReview-Commit-ID: 2kt3EN2WyXl
dom/base/Dispatcher.cpp
dom/base/Dispatcher.h
dom/base/DocGroup.cpp
dom/base/DocGroup.h
dom/base/TabGroup.cpp
dom/base/TabGroup.h
dom/base/nsDocument.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIDocument.h
--- a/dom/base/Dispatcher.cpp
+++ b/dom/base/Dispatcher.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "mozilla/dom/Dispatcher.h"
+
+#include "mozilla/AbstractThread.h"
 #include "mozilla/Move.h"
 #include "nsINamed.h"
 #include "nsQueryObject.h"
 
 using namespace mozilla;
 
 nsresult
 DispatcherTrait::Dispatch(const char* aName,
@@ -31,16 +33,23 @@ DispatcherTrait::Dispatch(const char* aN
 
 nsIEventTarget*
 DispatcherTrait::EventTargetFor(TaskCategory aCategory) const
 {
   nsCOMPtr<nsIEventTarget> main = do_GetMainThread();
   return main;
 }
 
+AbstractThread*
+DispatcherTrait::AbstractMainThreadFor(TaskCategory aCategory)
+{
+  // Return non DocGroup version by default.
+  return AbstractThread::MainThread();
+}
+
 namespace {
 
 #define NS_DISPATCHEREVENTTARGET_IID \
 { 0xbf4e36c8, 0x7d04, 0x4ef4, \
   { 0xbb, 0xd8, 0x11, 0x09, 0x0a, 0xdb, 0x4d, 0xf7 } }
 
 class DispatcherEventTarget final : public nsIEventTarget
 {
--- a/dom/base/Dispatcher.h
+++ b/dom/base/Dispatcher.h
@@ -9,16 +9,17 @@
 
 #include "mozilla/AlreadyAddRefed.h"
 #include "nsISupports.h"
 
 class nsIEventTarget;
 class nsIRunnable;
 
 namespace mozilla {
+class AbstractThread;
 namespace dom {
 
 class TabGroup;
 class DocGroup;
 
 enum class TaskCategory {
   // User input (clicks, keypresses, etc.)
   UI,
@@ -55,30 +56,38 @@ public:
   virtual nsresult Dispatch(const char* aName,
                             TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable);
 
   // This method may or may not be safe off of the main thread. For nsIDocument
   // it is safe. For nsIGlobalWindow it is not safe. The nsIEventTarget can
   // always be used off the main thread.
   virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const;
+
+  // Must be called on the main thread. The AbstractThread can always be used
+  // off the main thread.
+  virtual AbstractThread* AbstractMainThreadFor(TaskCategory aCategory);
 };
 
 // Base class for DocGroup and TabGroup.
 class Dispatcher : public nsISupports {
 public:
   // This method is always safe to call off the main thread.
   virtual nsresult Dispatch(const char* aName,
                             TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) = 0;
 
   // This method is always safe to call off the main thread. The nsIEventTarget
   // can always be used off the main thread.
   virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const = 0;
 
+  // Must be called on the main thread. The AbstractThread can always be used
+  // off the main thread.
+  virtual AbstractThread* AbstractMainThreadFor(TaskCategory aCategory) = 0;
+
   // These methods perform a safe cast. They return null if |this| is not of the
   // requested type.
   virtual TabGroup* AsTabGroup() { return nullptr; }
 
 protected:
   virtual already_AddRefed<nsIEventTarget>
   CreateEventTargetFor(TaskCategory aCategory);
 
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -74,10 +74,17 @@ DocGroup::Dispatch(const char* aName,
 }
 
 nsIEventTarget*
 DocGroup::EventTargetFor(TaskCategory aCategory) const
 {
   return mTabGroup->EventTargetFor(aCategory);
 }
 
+AbstractThread*
+DocGroup::AbstractMainThreadFor(TaskCategory aCategory)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  return mTabGroup->AbstractMainThreadFor(aCategory);
+}
+
 }
 }
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -12,16 +12,17 @@
 #include "nsIPrincipal.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 
 #include "mozilla/dom/Dispatcher.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
+class AbstractThread;
 namespace dom {
 
 // Two browsing contexts are considered "related" if they are reachable from one
 // another through window.opener, window.parent, or window.frames. This is the
 // spec concept of a "unit of related browsing contexts"
 //
 // Two browsing contexts are considered "similar-origin" if they can be made to
 // have the same origin by setting document.domain. This is the spec concept of
@@ -71,16 +72,19 @@ public:
   }
 
   virtual nsresult Dispatch(const char* aName,
                             TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override;
 
+  virtual AbstractThread*
+  AbstractMainThreadFor(TaskCategory aCategory) override;
+
 private:
   DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
   ~DocGroup();
 
   nsCString mKey;
   RefPtr<TabGroup> mTabGroup;
   nsTArray<nsIDocument*> mDocuments;
 };
--- a/dom/base/TabGroup.cpp
+++ b/dom/base/TabGroup.cpp
@@ -4,16 +4,17 @@
  * 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 "mozilla/dom/TabGroup.h"
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/DocGroup.h"
+#include "mozilla/AbstractThread.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "nsIDocShell.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIURI.h"
 
@@ -176,16 +177,17 @@ TabGroup::Leave(nsPIDOMWindowOuter* aWin
     mLastWindowLeft = true;
 
     // There is a RefPtr cycle TabGroup -> DispatcherEventTarget -> TabGroup. To
     // avoid leaks, we need to break the chain somewhere. We shouldn't be using
     // the ThrottledEventQueue for this TabGroup when no windows belong to it,
     // so it's safe to null out the queue here.
     for (size_t i = 0; i < size_t(TaskCategory::Count); i++) {
       mEventTargets[i] = nullptr;
+      mAbstractThreads[i] = nullptr;
     }
   }
 }
 
 nsresult
 TabGroup::FindItemWithName(const nsAString& aName,
                            nsIDocShellTreeItem* aRequestor,
                            nsIDocShellTreeItem* aOriginalRequestor,
@@ -261,24 +263,48 @@ TabGroup::Dispatch(const char* aName,
   } else {
     return NS_DispatchToMainThread(runnable.forget());
   }
 }
 
 nsIEventTarget*
 TabGroup::EventTargetFor(TaskCategory aCategory) const
 {
+  MOZ_ASSERT(aCategory != TaskCategory::Count);
   if (aCategory == TaskCategory::Worker || aCategory == TaskCategory::Timer) {
     MOZ_RELEASE_ASSERT(mThrottledQueuesInitialized || this == sChromeTabGroup);
   }
 
   if (NS_WARN_IF(mLastWindowLeft)) {
     // Once we've disconnected everything, we still allow people to
     // dispatch. We'll just go directly to the main thread.
     nsCOMPtr<nsIEventTarget> main = do_GetMainThread();
     return main;
   }
 
   return mEventTargets[size_t(aCategory)];
 }
 
+AbstractThread*
+TabGroup::AbstractMainThreadFor(TaskCategory aCategory)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aCategory != TaskCategory::Count);
+
+  // The mEventTargets of the chrome TabGroup are all set to do_GetMainThread().
+  // We could just return AbstractThread::MainThread() without a wrapper.
+  // Once we've disconnected everything, we still allow people to dispatch.
+  // We'll just go directly to the main thread.
+  if (this == sChromeTabGroup || NS_WARN_IF(mLastWindowLeft)) {
+    return AbstractThread::MainThread();
+  }
+
+  if (!mAbstractThreads[size_t(aCategory)]) {
+    mAbstractThreads[size_t(aCategory)] =
+      AbstractThread::CreateEventTargetWrapper(mEventTargets[size_t(aCategory)],
+                                               /* aDrainDirectTasks = */ true);
+  }
+
+  return mAbstractThreads[size_t(aCategory)];
+}
+
 }
 }
--- a/dom/base/TabGroup.h
+++ b/dom/base/TabGroup.h
@@ -13,16 +13,17 @@
 #include "nsTHashtable.h"
 #include "nsString.h"
 
 #include "mozilla/Atomics.h"
 #include "mozilla/dom/Dispatcher.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
+class AbstractThread;
 class ThrottledEventQueue;
 namespace dom {
 
 // Two browsing contexts are considered "related" if they are reachable from one
 // another through window.opener, window.parent, or window.frames. This is the
 // spec concept of a "unit of related browsing contexts"
 //
 // Two browsing contexts are considered "similar-origin" if they can be made to
@@ -116,23 +117,27 @@ public:
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   // This method is always safe to call off the main thread. The nsIEventTarget
   // can always be used off the main thread.
   virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override;
 
   TabGroup* AsTabGroup() override { return this; }
 
+  virtual AbstractThread*
+  AbstractMainThreadFor(TaskCategory aCategory) override;
+
 private:
   void EnsureThrottledEventQueues();
 
   ~TabGroup();
   DocGroupMap mDocGroups;
   Atomic<bool> mLastWindowLeft;
   nsTArray<nsPIDOMWindowOuter*> mWindows;
   Atomic<bool> mThrottledQueuesInitialized;
   nsCOMPtr<nsIEventTarget> mEventTargets[size_t(TaskCategory::Count)];
+  RefPtr<AbstractThread> mAbstractThreads[size_t(TaskCategory::Count)];
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // defined(TabGroup_h)
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2896,16 +2896,26 @@ nsIEventTarget*
 nsIDocument::EventTargetFor(TaskCategory aCategory) const
 {
   if (mDocGroup) {
     return mDocGroup->EventTargetFor(aCategory);
   }
   return DispatcherTrait::EventTargetFor(aCategory);
 }
 
+AbstractThread*
+nsIDocument::AbstractMainThreadFor(mozilla::dom::TaskCategory aCategory)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mDocGroup) {
+    return mDocGroup->AbstractMainThreadFor(aCategory);
+  }
+  return DispatcherTrait::AbstractMainThreadFor(aCategory);
+}
+
 void
 nsIDocument::NoteScriptTrackingStatus(const nsACString& aURL, bool aIsTracking)
 {
   if (aIsTracking) {
     mTrackingScripts.PutEntry(aURL);
   } else {
     MOZ_ASSERT(!mTrackingScripts.Contains(aURL));
   }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -14290,16 +14290,26 @@ nsGlobalWindow::EventTargetFor(TaskCateg
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (GetDocGroup()) {
     return GetDocGroup()->EventTargetFor(aCategory);
   }
   return DispatcherTrait::EventTargetFor(aCategory);
 }
 
+AbstractThread*
+nsGlobalWindow::AbstractMainThreadFor(TaskCategory aCategory)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (GetDocGroup()) {
+    return GetDocGroup()->AbstractMainThreadFor(aCategory);
+  }
+  return DispatcherTrait::AbstractMainThreadFor(aCategory);
+}
+
 nsGlobalWindow::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
   nsGlobalWindow* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
   MOZ_ASSERT(aWindow);
   nsGlobalWindow* topWindow = aWindow->GetScriptableTopInternal();
   if (!topWindow) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -98,16 +98,17 @@ class nsGlobalWindowObserver;
 class nsGlobalWindow;
 class nsDOMWindowUtils;
 class nsIIdleService;
 struct nsRect;
 
 class nsWindowSizes;
 
 namespace mozilla {
+class AbstractThread;
 class DOMEventTargetHelper;
 class ThrottledEventQueue;
 namespace dom {
 class BarProp;
 struct ChannelPixelLayout;
 class Console;
 class Crypto;
 class CustomElementRegistry;
@@ -1770,16 +1771,19 @@ public:
   // Dispatch a runnable related to the global.
   virtual nsresult Dispatch(const char* aName,
                             mozilla::dom::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsIEventTarget*
   EventTargetFor(mozilla::dom::TaskCategory aCategory) const override;
 
+  virtual mozilla::AbstractThread*
+  AbstractMainThreadFor(mozilla::dom::TaskCategory aCategory) override;
+
 protected:
   // These members are only used on outer window objects. Make sure
   // you never set any of these on an inner object!
   bool                          mFullScreen : 1;
   bool                          mFullscreenMode : 1;
   bool                          mIsClosed : 1;
   bool                          mInClose : 1;
   // mHavePendingClose means we've got a termination function set to
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -97,16 +97,17 @@ class nsSMILAnimationController;
 class nsTextNode;
 class nsWindowSizes;
 class nsDOMCaretPosition;
 class nsViewportInfo;
 class nsIGlobalObject;
 struct nsCSSSelectorList;
 
 namespace mozilla {
+class AbstractThread;
 class CSSStyleSheet;
 class ErrorResult;
 class EventStates;
 class PendingAnimationTracker;
 class StyleSetHandle;
 class SVGAttrAnimationRuleProcessor;
 template<typename> class OwningNonNull;
 
@@ -2878,16 +2879,19 @@ public:
   // Dispatch a runnable related to the document.
   virtual nsresult Dispatch(const char* aName,
                             mozilla::dom::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsIEventTarget*
   EventTargetFor(mozilla::dom::TaskCategory aCategory) const override;
 
+  virtual mozilla::AbstractThread*
+  AbstractMainThreadFor(mozilla::dom::TaskCategory aCategory) override;
+
   // The URLs passed to these functions should match what
   // JS::DescribeScriptedCaller() returns, since these APIs are used to
   // determine whether some code is being called from a tracking script.
   void NoteScriptTrackingStatus(const nsACString& aURL, bool isTracking);
   bool IsScriptTracking(const nsACString& aURL) const;
 
   bool PrerenderHref(nsIURI* aHref);