Bug 1154231 - Part 2. Reclaim cached resources when memory-pressure occurs. r=mattwoodrow
authorKan-Ru Chen <kanru@kanru.info>
Wed, 20 May 2015 15:45:41 +0800
changeset 275865 b9d272c24804375749013dd7c5d54ecad8a3cc48
parent 275864 77655fe1aab56a3c4cc7a631aa8e3e1c2b6e866a
child 275866 85b2d662f614b2089cbd7d7bb4b1d93ee1d868f1
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1154231
milestone41.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 1154231 - Part 2. Reclaim cached resources when memory-pressure occurs. r=mattwoodrow
widget/PuppetWidget.cpp
widget/PuppetWidget.h
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -70,16 +70,17 @@ MightNeedIMEFocus(const nsWidgetInitData
 
 // Arbitrary, fungible.
 const size_t PuppetWidget::kMaxDimension = 4000;
 
 NS_IMPL_ISUPPORTS_INHERITED0(PuppetWidget, nsBaseWidget)
 
 PuppetWidget::PuppetWidget(TabChild* aTabChild)
   : mTabChild(aTabChild)
+  , mMemoryPressureObserver(nullptr)
   , mDPI(-1)
   , mDefaultScale(-1)
   , mNativeKeyCommandsValid(false)
   , mCursorHotspotX(0)
   , mCursorHotspotY(0)
 {
   MOZ_COUNT_CTOR(PuppetWidget);
 
@@ -115,16 +116,21 @@ PuppetWidget::Create(nsIWidget        *a
   PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
   if (parent) {
     parent->SetChild(this);
     mLayerManager = parent->GetLayerManager();
   }
   else {
     Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
   }
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    mMemoryPressureObserver = new MemoryPressureObserver(this);
+    obs->AddObserver(mMemoryPressureObserver, "memory-pressure", false);
+  }
 
   return NS_OK;
 }
 
 void
 PuppetWidget::InitIMEState()
 {
   MOZ_ASSERT(mTabChild);
@@ -150,16 +156,20 @@ PuppetWidget::CreateChild(const nsIntRec
 }
 
 NS_IMETHODIMP
 PuppetWidget::Destroy()
 {
   Base::OnDestroy();
   Base::Destroy();
   mPaintTask.Revoke();
+  if (mMemoryPressureObserver) {
+    mMemoryPressureObserver->Remove();
+  }
+  mMemoryPressureObserver = nullptr;
   mChild = nullptr;
   if (mLayerManager) {
     mLayerManager->Destroy();
   }
   mLayerManager = nullptr;
   mTabChild = nullptr;
   return NS_OK;
 }
@@ -1078,16 +1088,46 @@ NS_IMETHODIMP
 PuppetWidget::PaintTask::Run()
 {
   if (mWidget) {
     mWidget->Paint();
   }
   return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(PuppetWidget::MemoryPressureObserver, nsIObserver)
+
+NS_IMETHODIMP
+PuppetWidget::MemoryPressureObserver::Observe(nsISupports* aSubject,
+                                              const char* aTopic,
+                                              const char16_t* aData)
+{
+  if (!mWidget) {
+    return NS_OK;
+  }
+
+  if (strcmp("memory-pressure", aTopic) == 0) {
+    if (!mWidget->mVisible && mWidget->mLayerManager &&
+        XRE_GetProcessType() == GeckoProcessType_Content) {
+      mWidget->mLayerManager->ClearCachedResources();
+    }
+  }
+  return NS_OK;
+}
+
+void
+PuppetWidget::MemoryPressureObserver::Remove()
+{
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, "memory-pressure");
+  }
+  mWidget = nullptr;
+}
+
 bool
 PuppetWidget::NeedsPaint()
 {
   // e10s popups are handled by the parent process, so never should be painted here
   if (XRE_GetProcessType() == GeckoProcessType_Content &&
       Preferences::GetBool("browser.tabs.remote.desktopbehavior", false) &&
       mWindowType == eWindowType_popup) {
     NS_WARNING("Trying to paint an e10s popup in the child process!");
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -274,28 +274,41 @@ private:
   public:
     NS_DECL_NSIRUNNABLE
     explicit PaintTask(PuppetWidget* widget) : mWidget(widget) {}
     void Revoke() { mWidget = nullptr; }
   private:
     PuppetWidget* mWidget;
   };
 
+  class MemoryPressureObserver : public nsIObserver {
+  public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIOBSERVER
+    explicit MemoryPressureObserver(PuppetWidget* aWidget) : mWidget(aWidget) {}
+    void Remove();
+  private:
+    virtual ~MemoryPressureObserver() {}
+    PuppetWidget* mWidget;
+  };
+  friend class MemoryPressureObserver;
+
   // TabChild normally holds a strong reference to this PuppetWidget
   // or its root ancestor, but each PuppetWidget also needs a
   // reference back to TabChild (e.g. to delegate nsIWidget IME calls
   // to chrome) So we hold a weak reference to TabChild here.  Since
   // it's possible for TabChild to outlive the PuppetWidget, we clear
   // this weak reference in Destroy()
   TabChild* mTabChild;
   // The "widget" to which we delegate events if we don't have an
   // event handler.
   nsRefPtr<PuppetWidget> mChild;
   nsIntRegion mDirtyRegion;
   nsRevocableEventPtr<PaintTask> mPaintTask;
+  nsRefPtr<MemoryPressureObserver> mMemoryPressureObserver;
   // XXX/cjones: keeping this around until we teach LayerManager to do
   // retained-content-only transactions
   mozilla::RefPtr<DrawTarget> mDrawTarget;
   // IME
   nsIMEUpdatePreference mIMEPreferenceOfParent;
   // Latest seqno received through events
   uint32_t mIMELastReceivedSeqno;
   // Chrome's seqno value when last blur occurred