Bug 1300659 P2 Expose a ThrottledEventQueue on TabGroup and nsPIDOMWindow. r=smaug
authorBen Kelly <ben@wanderview.com>
Mon, 07 Nov 2016 12:30:17 -0800
changeset 351617 a7b4c0d350ef04a8e33fcb98b680a8b103d453b8
parent 351616 537dea427441823141e1c83fc6b4dc215b94f063
child 351618 00efae73e570689a72761918362c2e0e1e819183
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)
reviewerssmaug
bugs1300659
milestone52.0a1
Bug 1300659 P2 Expose a ThrottledEventQueue on TabGroup and nsPIDOMWindow. r=smaug
dom/base/TabGroup.cpp
dom/base/TabGroup.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsPIDOMWindow.h
--- a/dom/base/TabGroup.cpp
+++ b/dom/base/TabGroup.cpp
@@ -1,36 +1,60 @@
+/* -*- 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/TabGroup.h"
+
 #include "mozilla/dom/DocGroup.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"
-#include "nsIEffectiveTLDService.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/ClearOnShutdown.h"
-#include "nsIDocShell.h"
 
 namespace mozilla {
 namespace dom {
 
-TabGroup::TabGroup()
-{}
+static StaticRefPtr<TabGroup> sChromeTabGroup;
+
+TabGroup::TabGroup(bool aIsChrome)
+{
+  // Do not throttle runnables from chrome windows.  In theory we should
+  // not have abuse issues from these windows and many browser chrome
+  // tests have races that fail if we do throttle chrome runnables.
+  if (aIsChrome) {
+    MOZ_ASSERT(!sChromeTabGroup);
+    return;
+  }
+
+  nsCOMPtr<nsIThread> mainThread;
+  NS_GetMainThread(getter_AddRefs(mainThread));
+  MOZ_DIAGNOSTIC_ASSERT(mainThread);
+
+  // This may return nullptr during xpcom shutdown.  This is ok as we
+  // do not guarantee a ThrottledEventQueue will be present.
+  mThrottledEventQueue = ThrottledEventQueue::Create(mainThread);
+}
 
 TabGroup::~TabGroup()
 {
   MOZ_ASSERT(mDocGroups.IsEmpty());
   MOZ_ASSERT(mWindows.IsEmpty());
 }
 
-static StaticRefPtr<TabGroup> sChromeTabGroup;
-
 TabGroup*
 TabGroup::GetChromeTabGroup()
 {
   if (!sChromeTabGroup) {
-    sChromeTabGroup = new TabGroup();
+    sChromeTabGroup = new TabGroup(true /* chrome tab group */);
     ClearOnShutdown(&sChromeTabGroup);
   }
   return sChromeTabGroup;
 }
 
 already_AddRefed<DocGroup>
 TabGroup::GetDocGroup(const nsACString& aKey)
 {
@@ -125,16 +149,22 @@ TabGroup::GetTopLevelWindows()
     if (!outerWindow->GetScriptableParentOrNull()) {
       array.AppendElement(outerWindow);
     }
   }
 
   return array;
 }
 
+ThrottledEventQueue*
+TabGroup::GetThrottledEventQueue() const
+{
+  return mThrottledEventQueue;
+}
+
 NS_IMPL_ISUPPORTS(TabGroup, nsISupports)
 
 TabGroup::HashEntry::HashEntry(const nsACString* aKey)
   : nsCStringHashKey(aKey), mDocGroup(nullptr)
 {}
 
 }
 }
--- a/dom/base/TabGroup.h
+++ b/dom/base/TabGroup.h
@@ -11,16 +11,17 @@
 #include "nsISupportsImpl.h"
 #include "nsIPrincipal.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
+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
 // have the same origin by setting document.domain. This is the spec concept of
@@ -53,17 +54,17 @@ public:
 
   friend class DocGroup;
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
   static TabGroup*
   GetChromeTabGroup();
 
-  TabGroup();
+  explicit TabGroup(bool aIsChrome = false);
 
   // Get the docgroup for the corresponding doc group key.
   // Returns null if the given key hasn't been seen yet.
   already_AddRefed<DocGroup>
   GetDocGroup(const nsACString& aKey);
 
   already_AddRefed<DocGroup>
   AddDocument(const nsACString& aKey, nsIDocument* aDocument);
@@ -94,18 +95,24 @@ public:
   nsresult
   FindItemWithName(const nsAString& aName,
                    nsIDocShellTreeItem* aRequestor,
                    nsIDocShellTreeItem* aOriginalRequestor,
                    nsIDocShellTreeItem** aFoundItem);
 
   nsTArray<nsPIDOMWindowOuter*> GetTopLevelWindows();
 
+  // Get the event queue that associated windows can use to issue runnables to
+  // the main thread.  This may return nullptr during browser shutdown.
+  ThrottledEventQueue*
+  GetThrottledEventQueue() const;
+
 private:
   ~TabGroup();
   DocGroupMap mDocGroups;
   nsTArray<nsPIDOMWindowOuter*> mWindows;
+  RefPtr<ThrottledEventQueue> mThrottledEventQueue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // defined(TabGroup_h)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -75,16 +75,17 @@
 #include "mozilla/dom/ToJSValue.h"
 #include "nsJSPrincipals.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Debug.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/ProcessHangMonitor.h"
+#include "mozilla/ThrottledEventQueue.h"
 #include "AudioChannelService.h"
 #include "nsAboutProtocolUtils.h"
 #include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
 #include "PostMessageEvent.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 
 // Interfaces Needed
@@ -9511,16 +9512,28 @@ nsGlobalWindow::UpdateCommands(const nsA
       nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
                                                             anAction));
     }
   }
 
   return NS_OK;
 }
 
+ThrottledEventQueue*
+nsGlobalWindow::GetThrottledEventQueue()
+{
+  // We must have an outer to access the TabGroup.
+  nsGlobalWindow* outer = GetOuterWindowInternal();
+  if (!outer) {
+    return nullptr;
+  }
+
+  return TabGroup()->GetThrottledEventQueue();
+}
+
 Selection*
 nsGlobalWindow::GetSelectionOuter()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   if (!mDocShell) {
     return nullptr;
   }
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -98,16 +98,17 @@ class nsGlobalWindow;
 class nsDOMWindowUtils;
 class nsIIdleService;
 struct nsRect;
 
 class nsWindowSizes;
 
 namespace mozilla {
 class DOMEventTargetHelper;
+class ThrottledEventQueue;
 namespace dom {
 class BarProp;
 struct ChannelPixelLayout;
 class Console;
 class Crypto;
 class CustomElementRegistry;
 class DocGroup;
 class External;
@@ -1152,16 +1153,18 @@ public:
              const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
              mozilla::ErrorResult& aError);
   nsresult OpenDialog(const nsAString& aUrl, const nsAString& aName,
                       const nsAString& aOptions,
                       nsISupports* aExtraArgument,
                       nsPIDOMWindowOuter** _retval) override;
   nsresult UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) override;
 
+  mozilla::ThrottledEventQueue* GetThrottledEventQueue() override;
+
   already_AddRefed<nsPIDOMWindowOuter>
     GetContentInternal(mozilla::ErrorResult& aError, bool aUnprivilegedCaller);
   void GetContentOuter(JSContext* aCx,
                        JS::MutableHandle<JSObject*> aRetval,
                        mozilla::ErrorResult& aError);
   void GetContent(JSContext* aCx,
                   JS::MutableHandle<JSObject*> aRetval,
                   mozilla::ErrorResult& aError);
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -35,16 +35,17 @@ class nsIURI;
 class nsPIDOMWindowInner;
 class nsPIDOMWindowOuter;
 class nsPIWindowRoot;
 class nsXBLPrototypeHandler;
 
 typedef uint32_t SuspendTypes;
 
 namespace mozilla {
+class ThrottledEventQueue;
 namespace dom {
 class AudioContext;
 class DocGroup;
 class TabGroup;
 class Element;
 class Performance;
 class ServiceWorkerRegistration;
 class Timeout;
@@ -576,16 +577,18 @@ public:
 
   virtual nsresult MoveBy(int32_t aXDif, int32_t aYDif) = 0;
   virtual nsresult UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) = 0;
 
   mozilla::dom::TabGroup* TabGroup();
 
   mozilla::dom::DocGroup* GetDocGroup();
 
+  virtual mozilla::ThrottledEventQueue* GetThrottledEventQueue() = 0;
+
 protected:
   // The nsPIDOMWindow constructor. The aOuterWindow argument should
   // be null if and only if the created window itself is an outer
   // window. In all other cases aOuterWindow should be the outer
   // window for the inner window that is being created.
   explicit nsPIDOMWindow<T>(nsPIDOMWindowOuter *aOuterWindow);
 
   ~nsPIDOMWindow<T>();