From da5496eedf82806a095b1cdad085128768797e30 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Mon, 6 Jun 2016 06:51:15 -0700 Subject: [PATCH] Bug 1273737: Shutdown the refresh driver when there are no more refresh drivers. r=dbaron,mchang --- layout/base/nsPresContext.cpp | 13 +++++------- layout/base/nsRefreshDriver.cpp | 36 +++++++++++++++++++++++++++----- layout/base/nsRefreshDriver.h | 11 ++++------ layout/build/nsLayoutStatics.cpp | 4 ---- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 42b4ac22ebdd..e5e33e655bb6 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -330,14 +330,7 @@ nsPresContext::Destroy() "nglayout.debug.paint_flashing_chrome", this); - // Disconnect the refresh driver *after* the transition manager, which - // needs it. - if (mRefreshDriver) { - if (mRefreshDriver->PresContext() == this) { - mRefreshDriver->Disconnect(); - } - mRefreshDriver = nullptr; - } + mRefreshDriver = nullptr; } nsPresContext::~nsPresContext() @@ -982,6 +975,10 @@ nsPresContext::SetShell(nsIPresShell* aShell) mRestyleManager->Disconnect(); mRestyleManager = nullptr; } + if (mRefreshDriver && mRefreshDriver->PresContext() == this) { + mRefreshDriver->Disconnect(); + // Can't null out the refresh driver here. + } if (IsRoot()) { nsRootPresContext* thisRoot = static_cast(this); diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index a070f4c92f07..644e3397ab26 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -104,6 +104,11 @@ namespace { // vsync to the main thread has been delayed by at least 2^i ms. Use // GetJankLevels to grab a copy of this array. uint64_t sJankLevels[12]; + + // The number outstanding nsRefreshDrivers (that have been created but not + // disconnected). When this reaches zero we will call + // nsRefreshDriver::Shutdown. + static uint32_t sRefreshDriverCount = 0; } namespace mozilla { @@ -889,11 +894,6 @@ GetFirstFrameDelay(imgIRequest* req) return static_cast(delay); } -/* static */ void -nsRefreshDriver::InitializeStatics() -{ -} - /* static */ void nsRefreshDriver::Shutdown() { @@ -1024,18 +1024,29 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext) mSkippedPaints(false), mResizeSuppressed(false) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mPresContext, + "Need a pres context to tell us to call Disconnect() later " + "and decrement sRefreshDriverCount."); + mMostRecentRefreshEpochTime = JS_Now(); mMostRecentRefresh = TimeStamp::Now(); mMostRecentTick = mMostRecentRefresh; mNextThrottledFrameRequestTick = mMostRecentTick; mNextRecomputeVisibilityTick = mMostRecentTick; + + --sRefreshDriverCount; } nsRefreshDriver::~nsRefreshDriver() { + MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(ObserverCount() == 0, "observers should have unregistered"); MOZ_ASSERT(!mActiveTimer, "timer should be gone"); + MOZ_ASSERT(!mPresContext, + "Should have called Disconnect() and decremented " + "sRefreshDriverCount!"); if (mRootRefresh) { mRootRefresh->RemoveRefreshObserver(this, Flush_Style); @@ -2207,6 +2218,21 @@ nsRefreshDriver::CancelPendingEvents(nsIDocument* aDocument) } } +void +nsRefreshDriver::Disconnect() +{ + MOZ_ASSERT(NS_IsMainThread()); + + StopTimer(); + + if (mPresContext) { + mPresContext = nullptr; + if (--sRefreshDriverCount == 0) { + Shutdown(); + } + } +} + /* static */ bool nsRefreshDriver::IsJankCritical() { diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h index cff0c19ea7d1..218d2026ab1c 100644 --- a/layout/base/nsRefreshDriver.h +++ b/layout/base/nsRefreshDriver.h @@ -77,9 +77,6 @@ public: explicit nsRefreshDriver(nsPresContext *aPresContext); ~nsRefreshDriver(); - static void InitializeStatics(); - static void Shutdown(); - /** * Methods for testing, exposed via nsIDOMWindowUtils. See * nsIDOMWindowUtils.advanceTimeAndRefresh for description. @@ -248,10 +245,7 @@ public: * should stop its timer and forget about its pres context. This may * be called from within a refresh. */ - void Disconnect() { - StopTimer(); - mPresContext = nullptr; - } + void Disconnect(); bool IsFrozen() { return mFreezeCount > 0; } @@ -334,6 +328,7 @@ public: NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override { return TransactionIdAllocator::AddRef(); } NS_IMETHOD_(MozExternalRefCountType) Release(void) override { return TransactionIdAllocator::Release(); } virtual void WillRefresh(mozilla::TimeStamp aTime) override; + private: typedef nsTObserverArray ObserverArray; typedef nsTHashtable RequestTable; @@ -463,6 +458,8 @@ private: void ConfigureHighPrecision(); void SetHighPrecisionTimersEnabled(bool aEnable); + static void Shutdown(); + // `true` if we are currently in jank-critical mode. // // In jank-critical mode, any iteration of the event loop that takes diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index fd51537639ac..99e05c4d9b95 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -109,7 +109,6 @@ using namespace mozilla::system; #include "nsJSEnvironment.h" #include "nsContentSink.h" #include "nsFrameMessageManager.h" -#include "nsRefreshDriver.h" #include "nsDOMMutationObserver.h" #include "nsHyphenationManager.h" #include "nsEditorSpellCheck.h" @@ -271,7 +270,6 @@ nsLayoutStatics::Initialize() nsLayoutUtils::Initialize(); nsIPresShell::InitializeStatics(); TouchManager::InitializeStatics(); - nsRefreshDriver::InitializeStatics(); nsPrincipal::InitializeStatics(); nsCORSListenerProxy::Startup(); @@ -434,8 +432,6 @@ nsLayoutStatics::Shutdown() ContentParent::ShutDown(); - nsRefreshDriver::Shutdown(); - DisplayItemClip::Shutdown(); nsDocument::XPCOMShutdown();