Bug 1340771 part 2 - Introduce a WeakFrame class for heap allocated weak frame pointers, stored in a hashtable for fast lookup. r=tn
authorMats Palmgren <mats@mozilla.com>
Wed, 01 Mar 2017 18:03:14 +0100
changeset 394507 cb8eb0ca05acd0dcded6012c5e5ec0f7d6813c6b
parent 394506 75caefd9df14d0cbede0a99fcbac80d389461d03
child 394508 3cf51d656aef11c9a9d2bb8bc91cb08cd4fa7637
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1340771
milestone54.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 1340771 part 2 - Introduce a WeakFrame class for heap allocated weak frame pointers, stored in a hashtable for fast lookup. r=tn * * * Bug 1340771 part 3 - Change existing heap allocated AutoWeakFrame instances to use WeakFrame instead. r=tn MozReview-Commit-ID: GSuUiy98jBa
accessible/base/SelectionManager.h
dom/base/nsFrameLoader.h
dom/base/nsObjectLoadingContent.h
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
layout/base/PresShell.cpp
layout/base/nsIPresShell.h
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsDateTimeControlFrame.h
layout/forms/nsFileControlFrame.h
layout/forms/nsNumberControlFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsSubDocumentFrame.cpp
layout/painting/ActiveLayerTracker.cpp
layout/printing/nsPrintEngine.h
layout/tables/nsTableFrame.cpp
layout/xul/nsListBoxBodyFrame.cpp
layout/xul/nsListBoxBodyFrame.h
layout/xul/nsMenuFrame.cpp
layout/xul/nsProgressMeterFrame.cpp
layout/xul/nsTextBoxFrame.cpp
layout/xul/nsTextBoxFrame.h
layout/xul/nsXULPopupManager.cpp
layout/xul/tree/nsTreeBodyFrame.cpp
--- a/accessible/base/SelectionManager.h
+++ b/accessible/base/SelectionManager.h
@@ -116,17 +116,17 @@ protected:
 
   /**
    * Process DOM selection change. Fire selection and caret move events.
    */
   void ProcessSelectionChanged(SelData* aSelData);
 
 private:
   // Currently focused control.
-  AutoWeakFrame mCurrCtrlFrame;
+  WeakFrame mCurrCtrlFrame;
   int32_t mCaretOffset;
   HyperTextAccessible* mAccWithCaret;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -324,17 +324,17 @@ private:
 
   // After the frameloader has been removed from the DOM but before all of the
   // messages from the frame have been received, we keep a strong reference to
   // our <browser> element.
   RefPtr<mozilla::dom::Element> mOwnerContentStrong;
 
   // Stores the root frame of the subdocument while the subdocument is being
   // reframed. Used to restore the presentation after reframing.
-  AutoWeakFrame mDetachedSubdocFrame;
+  WeakFrame mDetachedSubdocFrame;
   // Stores the containing document of the frame corresponding to this
   // frame loader. This is reference is kept valid while the subframe's
   // presentation is detached and stored in mDetachedSubdocFrame. This
   // enables us to detect whether the frame has moved documents during
   // a reframe, so that we know not to restore the presentation.
   nsCOMPtr<nsIDocument> mContainerDocWhileDetached;
 
   // An opener window which should be used when the docshell is created.
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -710,16 +710,16 @@ class nsObjectLoadingContent : public ns
     // videos.
     bool                        mRewrittenYoutubeEmbed : 1;
 
     // Cache the answer of PreferFallback() because ShouldPlay is called several
     // times during the load process.
     bool                        mPreferFallback : 1;
     bool                        mPreferFallbackKnown : 1;
 
-    AutoWeakFrame                 mPrintFrame;
+    WeakFrame                   mPrintFrame;
 
     RefPtr<nsPluginInstanceOwner> mInstanceOwner;
     nsTArray<mozilla::dom::MozPluginParameter> mCachedAttributes;
     nsTArray<mozilla::dom::MozPluginParameter> mCachedParameters;
 };
 
 #endif
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4445,18 +4445,19 @@ EventStateManager::GenerateDragDropEnter
             WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
                                         aDragEvent->mWidget);
             remoteEvent.AssignDragEventData(*aDragEvent, true);
             nsEventStatus remoteStatus = nsEventStatus_eIgnore;
             HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
           }
         }
 
+        AutoWeakFrame currentTraget = mCurrentTarget;
         FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter,
-                            lastContent, targetContent, mCurrentTarget);
+                            lastContent, targetContent, currentTraget);
 
         if (sLastDragOverFrame) {
           FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
                               aDragEvent, eDragLeave,
                               targetContent, lastContent, sLastDragOverFrame);
         }
 
         sLastDragOverFrame = mCurrentTarget;
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -49,17 +49,17 @@ class OverOutElementsWrapper final : pub
   ~OverOutElementsWrapper();
 
 public:
   OverOutElementsWrapper();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(OverOutElementsWrapper)
 
-  AutoWeakFrame mLastOverFrame;
+  WeakFrame mLastOverFrame;
 
   nsCOMPtr<nsIContent> mLastOverElement;
 
   // The last element on which we fired a over event, or null if
   // the last over event we fired has finished processing.
   nsCOMPtr<nsIContent> mFirstOverEventElement;
 
   // The last element on which we fired a out event, or null if
@@ -925,17 +925,17 @@ private:
 
   // Stores the mRefPoint of the last synthetic mouse move we dispatched
   // to re-center the mouse when we were pointer locked. If this is (-1,-1) it
   // means we've not recently dispatched a centering event. We use this to
   // detect when we receive the synth event, so we can cancel and not send it
   // to content.
   static LayoutDeviceIntPoint sSynthCenteringPoint;
 
-  AutoWeakFrame mCurrentTarget;
+  WeakFrame mCurrentTarget;
   nsCOMPtr<nsIContent> mCurrentTargetContent;
   static AutoWeakFrame sLastDragOverFrame;
 
   // Stores the mRefPoint (the offset from the widget's origin in device
   // pixels) of the last mouse event.
   static LayoutDeviceIntPoint sLastRefPoint;
 
   // member variables for the d&d gesture state machine
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -660,53 +660,82 @@ nsIPresShell::GetVerifyReflowEnable()
 
 void
 nsIPresShell::SetVerifyReflowEnable(bool aEnabled)
 {
   gVerifyReflowEnabled = aEnabled;
 }
 
 /* virtual */ void
-nsIPresShell::AddWeakFrameExternal(AutoWeakFrame* aWeakFrame)
-{
-  AddWeakFrameInternal(aWeakFrame);
-}
-
-void
-nsIPresShell::AddWeakFrameInternal(AutoWeakFrame* aWeakFrame)
+nsIPresShell::AddAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame)
+{
+  AddAutoWeakFrameInternal(aWeakFrame);
+}
+
+void
+nsIPresShell::AddAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame)
 {
   if (aWeakFrame->GetFrame()) {
     aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
   }
-  aWeakFrame->SetPreviousWeakFrame(mWeakFrames);
-  mWeakFrames = aWeakFrame;
+  aWeakFrame->SetPreviousWeakFrame(mAutoWeakFrames);
+  mAutoWeakFrames = aWeakFrame;
 }
 
 /* virtual */ void
-nsIPresShell::RemoveWeakFrameExternal(AutoWeakFrame* aWeakFrame)
-{
-  RemoveWeakFrameInternal(aWeakFrame);
-}
-
-void
-nsIPresShell::RemoveWeakFrameInternal(AutoWeakFrame* aWeakFrame)
-{
-  if (mWeakFrames == aWeakFrame) {
-    mWeakFrames = aWeakFrame->GetPreviousWeakFrame();
-    return;
-  }
-  AutoWeakFrame* nextWeak = mWeakFrames;
+nsIPresShell::AddWeakFrameExternal(WeakFrame* aWeakFrame)
+{
+  AddWeakFrameInternal(aWeakFrame);
+}
+
+void
+nsIPresShell::AddWeakFrameInternal(WeakFrame* aWeakFrame)
+{
+  if (aWeakFrame->GetFrame()) {
+    aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
+  }
+  MOZ_ASSERT(!mWeakFrames.GetEntry(aWeakFrame));
+  mWeakFrames.PutEntry(aWeakFrame);
+}
+
+/* virtual */ void
+nsIPresShell::RemoveAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame)
+{
+  RemoveAutoWeakFrameInternal(aWeakFrame);
+}
+
+void
+nsIPresShell::RemoveAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame)
+{
+  if (mAutoWeakFrames == aWeakFrame) {
+    mAutoWeakFrames = aWeakFrame->GetPreviousWeakFrame();
+    return;
+  }
+  AutoWeakFrame* nextWeak = mAutoWeakFrames;
   while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
     nextWeak = nextWeak->GetPreviousWeakFrame();
   }
   if (nextWeak) {
     nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
   }
 }
 
+/* virtual */ void
+nsIPresShell::RemoveWeakFrameExternal(WeakFrame* aWeakFrame)
+{
+  RemoveWeakFrameInternal(aWeakFrame);
+}
+
+void
+nsIPresShell::RemoveWeakFrameInternal(WeakFrame* aWeakFrame)
+{
+  MOZ_ASSERT(mWeakFrames.GetEntry(aWeakFrame));
+  mWeakFrames.RemoveEntry(aWeakFrame);
+}
+
 already_AddRefed<nsFrameSelection>
 nsIPresShell::FrameSelection()
 {
   RefPtr<nsFrameSelection> ret = mSelection;
   return ret.forget();
 }
 
 //----------------------------------------------------------------------
@@ -746,17 +775,17 @@ nsIPresShell::nsIPresShell()
     , mFrameManager(nullptr)
 #ifdef ACCESSIBILITY
     , mDocAccessible(nullptr)
 #endif
 #ifdef DEBUG
     , mDrawEventTargetFrame(nullptr)
 #endif
     , mPaintCount(0)
-    , mWeakFrames(nullptr)
+    , mAutoWeakFrames(nullptr)
     , mCanvasBackgroundColor(NS_RGBA(0,0,0,0))
     , mSelectionFlags(0)
     , mRenderFlags(0)
     , mStylesHaveChanged(false)
     , mDidInitialize(false)
     , mIsDestroying(false)
     , mIsReflowing(false)
     , mPaintingSuppressed(false)
@@ -1361,20 +1390,27 @@ PresShell::Destroy()
     // now dead, we shouldn't be looking up any more properties in that table.
     // We want to do this before we call DetachShell() on the prescontext, so
     // property destructors can usefully call GetPresShell() on the
     // prescontext.
     mPresContext->PropertyTable()->DeleteAll();
   }
 
 
-  NS_WARNING_ASSERTION(!mWeakFrames,
+  NS_WARNING_ASSERTION(!mAutoWeakFrames && mWeakFrames.IsEmpty(),
                        "Weak frames alive after destroying FrameManager");
-  while (mWeakFrames) {
-    mWeakFrames->Clear(this);
+  while (mAutoWeakFrames) {
+    mAutoWeakFrames->Clear(this);
+  }
+  nsTArray<WeakFrame*> toRemove(mWeakFrames.Count());
+  for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
+    toRemove.AppendElement(iter.Get()->GetKey());
+  }
+  for (WeakFrame* weakFrame : toRemove) {
+    weakFrame->Clear(this);
   }
 
   // Let the style set do its cleanup.
   mStyleSet->Shutdown();
 
   if (mPresContext) {
     // We hold a reference to the pres context, and it holds a weak link back
     // to us. To avoid the pres context having a dangling reference, set its
@@ -2944,25 +2980,36 @@ nsIPresShell::SetForwardingContainer(con
   mForwardingContainer = aContainer;
 }
 
 void
 PresShell::ClearFrameRefs(nsIFrame* aFrame)
 {
   mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
 
-  AutoWeakFrame* weakFrame = mWeakFrames;
+  AutoWeakFrame* weakFrame = mAutoWeakFrames;
   while (weakFrame) {
     AutoWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
     if (weakFrame->GetFrame() == aFrame) {
-      // This removes weakFrame from mWeakFrames.
+      // This removes weakFrame from mAutoWeakFrames.
       weakFrame->Clear(this);
     }
     weakFrame = prev;
   }
+
+  AutoTArray<WeakFrame*, 4> toRemove;
+  for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
+    WeakFrame* weakFrame = iter.Get()->GetKey();
+    if (weakFrame->GetFrame() == aFrame) {
+      toRemove.AppendElement(weakFrame);
+    }
+  }
+  for (WeakFrame* weakFrame : toRemove) {
+    weakFrame->Clear(this);
+  }
 }
 
 already_AddRefed<gfxContext>
 PresShell::CreateReferenceRenderingContext()
 {
   nsDeviceContext* devCtx = mPresContext->DeviceContext();
   RefPtr<gfxContext> rc;
   if (mPresContext->IsScreen()) {
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -74,16 +74,17 @@ class nsFrameSelection;
 class nsFrameManager;
 class nsILayoutHistoryState;
 class nsIReflowCallback;
 class nsIDOMNode;
 class nsCSSFrameConstructor;
 class nsISelection;
 template<class E> class nsCOMArray;
 class AutoWeakFrame;
+class WeakFrame;
 class nsIScrollableFrame;
 class gfxContext;
 class nsIDOMEvent;
 class nsDisplayList;
 class nsDisplayListBuilder;
 class nsPIDOMWindowOuter;
 struct nsPoint;
 class nsINode;
@@ -1187,32 +1188,52 @@ public:
    * frames.
    */
   virtual already_AddRefed<mozilla::gfx::SourceSurface>
   RenderSelection(nsISelection* aSelection,
                   const mozilla::LayoutDeviceIntPoint aPoint,
                   mozilla::LayoutDeviceIntRect* aScreenRect,
                   uint32_t aFlags) = 0;
 
-  void AddWeakFrameInternal(AutoWeakFrame* aWeakFrame);
-  virtual void AddWeakFrameExternal(AutoWeakFrame* aWeakFrame);
+  void AddAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame);
+  virtual void AddAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame);
+  void AddWeakFrameInternal(WeakFrame* aWeakFrame);
+  virtual void AddWeakFrameExternal(WeakFrame* aWeakFrame);
 
-  void AddWeakFrame(AutoWeakFrame* aWeakFrame)
+  void AddAutoWeakFrame(AutoWeakFrame* aWeakFrame)
+  {
+#ifdef MOZILLA_INTERNAL_API
+    AddAutoWeakFrameInternal(aWeakFrame);
+#else
+    AddAutoWeakFrameExternal(aWeakFrame);
+#endif
+  }
+  void AddWeakFrame(WeakFrame* aWeakFrame)
   {
 #ifdef MOZILLA_INTERNAL_API
     AddWeakFrameInternal(aWeakFrame);
 #else
     AddWeakFrameExternal(aWeakFrame);
 #endif
   }
 
-  void RemoveWeakFrameInternal(AutoWeakFrame* aWeakFrame);
-  virtual void RemoveWeakFrameExternal(AutoWeakFrame* aWeakFrame);
+  void RemoveAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame);
+  virtual void RemoveAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame);
+  void RemoveWeakFrameInternal(WeakFrame* aWeakFrame);
+  virtual void RemoveWeakFrameExternal(WeakFrame* aWeakFrame);
 
-  void RemoveWeakFrame(AutoWeakFrame* aWeakFrame)
+  void RemoveAutoWeakFrame(AutoWeakFrame* aWeakFrame)
+  {
+#ifdef MOZILLA_INTERNAL_API
+    RemoveAutoWeakFrameInternal(aWeakFrame);
+#else
+    RemoveAutoWeakFrameExternal(aWeakFrame);
+#endif
+  }
+  void RemoveWeakFrame(WeakFrame* aWeakFrame)
   {
 #ifdef MOZILLA_INTERNAL_API
     RemoveWeakFrameInternal(aWeakFrame);
 #else
     RemoveWeakFrameExternal(aWeakFrame);
 #endif
   }
 
@@ -1810,18 +1831,21 @@ protected:
 #endif
 
 
   // Count of the number of times this presshell has been painted to a window.
   uint64_t                  mPaintCount;
 
   nsSize                    mScrollPositionClampingScrollPortSize;
 
-  // A list of weak frames. This is a pointer to the last item in the list.
-  AutoWeakFrame*              mWeakFrames;
+  // A list of stack weak frames. This is a pointer to the last item in the list.
+  AutoWeakFrame*            mAutoWeakFrames;
+
+  // A hash table of heap allocated weak frames.
+  nsTHashtable<nsPtrHashKey<WeakFrame>> mWeakFrames;
 
   // Most recent canvas background color.
   nscolor                   mCanvasBackgroundColor;
 
   // Used to force allocation and rendering of proportionally more or
   // less pixels in both dimensions.
   mozilla::Maybe<float>     mResolution;
 
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -408,17 +408,17 @@ public:
   {
     if (mFrame.IsAlive()) {
       static_cast<nsComboboxControlFrame*>(mFrame.GetFrame())->
         AbsolutelyPositionDropDown();
     }
     return NS_OK;
   }
 
-  AutoWeakFrame mFrame;
+  WeakFrame mFrame;
 };
 
 void
 nsComboboxControlFrame::ReflowDropdown(nsPresContext*  aPresContext,
                                        const ReflowInput& aReflowInput)
 {
   // All we want out of it later on, really, is the block size of a row, so we
   // don't even need to cache mDropdownFrame's ascent or anything.  If we don't
@@ -522,17 +522,17 @@ public:
   NS_IMETHOD Run() override
   {
     if (mFrame.IsAlive()) {
       static_cast<nsComboboxControlFrame*>(mFrame.GetFrame())
         ->RollupFromList();
     }
     return NS_OK;
   }
-  AutoWeakFrame mFrame;
+  WeakFrame mFrame;
 };
 
 class nsAsyncResize : public Runnable
 {
 public:
   explicit nsAsyncResize(nsComboboxControlFrame* aFrame) : mFrame(aFrame) {}
   NS_IMETHOD Run() override
   {
@@ -551,17 +551,17 @@ public:
           SetSuppressScrollbarUpdate(false);
         if (combo->mDelayedShowDropDown) {
           combo->ShowDropDown(true);
         }
       }
     }
     return NS_OK;
   }
-  AutoWeakFrame mFrame;
+  WeakFrame mFrame;
 };
 
 void
 nsComboboxControlFrame::GetAvailableDropdownSpace(WritingMode aWM,
                                                   nscoord* aBefore,
                                                   nscoord* aAfter,
                                                   LogicalPoint* aTranslation)
 {
--- a/layout/forms/nsDateTimeControlFrame.h
+++ b/layout/forms/nsDateTimeControlFrame.h
@@ -98,17 +98,17 @@ private:
         static_cast<nsDateTimeControlFrame*>(mFrame.GetFrame());
       NS_ENSURE_STATE(frame);
 
       frame->SyncDisabledState();
       return NS_OK;
     }
 
   private:
-    AutoWeakFrame mFrame;
+    WeakFrame mFrame;
   };
 
   /**
    * Sync the disabled state of the anonymous children up with our content's.
    */
   void SyncDisabledState();
 
   // Anonymous child which is bound via XBL to an element that wraps the input
--- a/layout/forms/nsFileControlFrame.h
+++ b/layout/forms/nsFileControlFrame.h
@@ -106,17 +106,17 @@ protected:
       nsFileControlFrame* frame = static_cast<nsFileControlFrame*>(mFrame.GetFrame());
       NS_ENSURE_STATE(frame);
 
       frame->SyncDisabledState();
       return NS_OK;
     }
 
   private:
-    AutoWeakFrame mFrame;
+    WeakFrame mFrame;
   };
 
   class DnDListener: public MouseListener {
   public:
     explicit DnDListener(nsFileControlFrame* aFrame)
       : MouseListener(aFrame)
     {}
 
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -187,17 +187,17 @@ private:
         static_cast<nsNumberControlFrame*>(mFrame.GetFrame());
       NS_ENSURE_STATE(frame);
 
       frame->SyncDisabledState();
       return NS_OK;
     }
 
   private:
-    AutoWeakFrame mFrame;
+    WeakFrame mFrame;
   };
 
   /**
    * Sync the disabled state of the anonymous children up with our content's.
    */
   void SyncDisabledState();
 
   /**
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -401,25 +401,47 @@ nsIFrame::FindCloserFrameForSelection(
   }
 }
 
 void
 nsIFrame::ContentStatesChanged(mozilla::EventStates aStates)
 {
 }
 
+AutoWeakFrame::AutoWeakFrame(const WeakFrame& aOther)
+  : mPrev(nullptr), mFrame(nullptr)
+{
+  Init(aOther.GetFrame());
+}
+
 void
 AutoWeakFrame::Init(nsIFrame* aFrame)
 {
   Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
   mFrame = aFrame;
   if (mFrame) {
     nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
     NS_WARNING_ASSERTION(shell, "Null PresShell in AutoWeakFrame!");
     if (shell) {
+      shell->AddAutoWeakFrame(this);
+    } else {
+      mFrame = nullptr;
+    }
+  }
+}
+
+void
+WeakFrame::Init(nsIFrame* aFrame)
+{
+  Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
+  mFrame = aFrame;
+  if (mFrame) {
+    nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
+    MOZ_ASSERT(shell, "Null PresShell in WeakFrame!");
+    if (shell) {
       shell->AddWeakFrame(this);
     } else {
       mFrame = nullptr;
     }
   }
 }
 
 nsIFrame*
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3813,36 +3813,43 @@ public:
 #endif
 };
 
 //----------------------------------------------------------------------
 
 /**
  * AutoWeakFrame can be used to keep a reference to a nsIFrame in a safe way.
  * Whenever an nsIFrame object is deleted, the AutoWeakFrames pointing
- * to it will be cleared.
+ * to it will be cleared.  AutoWeakFrame is for variables on the stack or
+ * in static storage only, there is also a WeakFrame below for heap uses.
  *
  * Create AutoWeakFrame object when it is sure that nsIFrame object
  * is alive and after some operations which may destroy the nsIFrame
  * (for example any DOM modifications) use IsAlive() or GetFrame() methods to
  * check whether it is safe to continue to use the nsIFrame object.
  *
  * @note The usage of this class should be kept to a minimum.
  */
-
-class AutoWeakFrame {
+class WeakFrame;
+class AutoWeakFrame
+{
 public:
-  AutoWeakFrame() : mPrev(nullptr), mFrame(nullptr) { }
-
-  AutoWeakFrame(const AutoWeakFrame& aOther) : mPrev(nullptr), mFrame(nullptr)
+  explicit AutoWeakFrame()
+    : mPrev(nullptr), mFrame(nullptr) {}
+
+  AutoWeakFrame(const AutoWeakFrame& aOther)
+    : mPrev(nullptr), mFrame(nullptr)
   {
     Init(aOther.GetFrame());
   }
 
-  MOZ_IMPLICIT AutoWeakFrame(nsIFrame* aFrame) : mPrev(nullptr), mFrame(nullptr)
+  MOZ_IMPLICIT AutoWeakFrame(const WeakFrame& aOther);
+
+  MOZ_IMPLICIT AutoWeakFrame(nsIFrame* aFrame)
+    : mPrev(nullptr), mFrame(nullptr)
   {
     Init(aFrame);
   }
 
   AutoWeakFrame& operator=(AutoWeakFrame& aOther) {
     Init(aOther.GetFrame());
     return *this;
   }
@@ -3859,17 +3866,17 @@ public:
 
   operator nsIFrame*()
   {
     return mFrame;
   }
 
   void Clear(nsIPresShell* aShell) {
     if (aShell) {
-      aShell->RemoveWeakFrame(this);
+      aShell->RemoveAutoWeakFrame(this);
     }
     mFrame = nullptr;
     mPrev = nullptr;
   }
 
   bool IsAlive() { return !!mFrame; }
 
   nsIFrame* GetFrame() const { return mFrame; }
@@ -3878,20 +3885,83 @@ public:
 
   void SetPreviousWeakFrame(AutoWeakFrame* aPrev) { mPrev = aPrev; }
 
   ~AutoWeakFrame()
   {
     Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
   }
 private:
+  // Not available for the heap!
+  void* operator new(size_t) = delete;
+  void* operator new[](size_t) = delete;
+  void operator delete(void*) = delete;
+  void operator delete[](void*) = delete;
+
   void Init(nsIFrame* aFrame);
 
   AutoWeakFrame*  mPrev;
-  nsIFrame*     mFrame;
+  nsIFrame*       mFrame;
+};
+
+/**
+ * @see AutoWeakFrame
+ */
+class WeakFrame
+{
+public:
+  WeakFrame() : mFrame(nullptr) {}
+
+  WeakFrame(const WeakFrame& aOther) : mFrame(nullptr)
+  {
+    Init(aOther.GetFrame());
+  }
+
+  MOZ_IMPLICIT WeakFrame(const AutoWeakFrame& aOther) : mFrame(nullptr)
+  {
+    Init(aOther.GetFrame());
+  }
+
+  MOZ_IMPLICIT WeakFrame(nsIFrame* aFrame) : mFrame(nullptr)
+  {
+    Init(aFrame);
+  }
+
+  ~WeakFrame()
+  {
+    Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
+  }
+
+  WeakFrame& operator=(WeakFrame& aOther) {
+    Init(aOther.GetFrame());
+    return *this;
+  }
+
+  WeakFrame& operator=(nsIFrame* aFrame) {
+    Init(aFrame);
+    return *this;
+  }
+
+  nsIFrame* operator->() { return mFrame; }
+  operator nsIFrame*() { return mFrame; }
+
+  void Clear(nsIPresShell* aShell) {
+    if (aShell) {
+      aShell->RemoveWeakFrame(this);
+    }
+    mFrame = nullptr;
+  }
+
+  bool IsAlive() { return !!mFrame; }
+  nsIFrame* GetFrame() const { return mFrame; }
+
+private:
+  void Init(nsIFrame* aFrame);
+
+  nsIFrame* mFrame;
 };
 
 inline bool
 nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame)
 {
   MOZ_ASSERT(!aFrame->GetPrevSibling() || !aFrame->GetNextSibling(),
              "Forgot to call StartRemoveFrame?");
   if (aFrame == mLastChild) {
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -88,17 +88,17 @@ public:
   {
     PROFILER_LABEL("mozilla", "AsyncFrameInit::Run", js::ProfileEntry::Category::OTHER);
     if (mFrame.IsAlive()) {
       static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
     }
     return NS_OK;
   }
 private:
-  AutoWeakFrame mFrame;
+  WeakFrame mFrame;
 };
 
 static void
 InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent);
 
 static void
 EndSwapDocShellsForViews(nsView* aView);
 
--- a/layout/painting/ActiveLayerTracker.cpp
+++ b/layout/painting/ActiveLayerTracker.cpp
@@ -100,17 +100,17 @@ public:
 
   nsExpirationState mState;
 
   // Previous scale due to the CSS transform property.
   Maybe<gfxSize> mPreviousTransformScale;
 
   // The scroll frame during for which we most recently received a call to
   // NotifyAnimatedFromScrollHandler.
-  AutoWeakFrame mAnimatingScrollHandlerFrame;
+  WeakFrame mAnimatingScrollHandlerFrame;
   // The set of activities that were triggered during
   // mAnimatingScrollHandlerFrame's scroll event handler.
   EnumSet<ActivityIndex> mScrollHandlerInducedActivity;
 
   // Number of restyle operations detected
   uint8_t mRestyleCounts[ACTIVITY_COUNT];
   bool mContentActive;
 };
@@ -127,17 +127,17 @@ public:
   ~LayerActivityTracker() {
     mDestroying = true;
     AgeAllGenerations();
   }
 
   virtual void NotifyExpired(LayerActivity* aObject);
 
 public:
-  AutoWeakFrame mCurrentScrollHandlerFrame;
+  WeakFrame mCurrentScrollHandlerFrame;
 
 private:
   bool mDestroying;
 };
 
 static LayerActivityTracker* gLayerActivityTracker = nullptr;
 
 LayerActivity::~LayerActivity()
--- a/layout/printing/nsPrintEngine.h
+++ b/layout/printing/nsPrintEngine.h
@@ -258,17 +258,17 @@ protected:
   bool mProgressDialogIsShown;
 
   nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
   nsWeakPtr               mContainer;
   float                   mScreenDPI;
   
   mozilla::UniquePtr<nsPrintData> mPrt;
   nsPagePrintTimer*       mPagePrintTimer;
-  AutoWeakFrame             mPageSeqFrame;
+  WeakFrame               mPageSeqFrame;
 
   // Print Preview
   mozilla::UniquePtr<nsPrintData> mPrtPreview;
   mozilla::UniquePtr<nsPrintData> mOldPrtPreview;
 
   nsCOMPtr<nsIDocument>   mDocument;
 
   FILE* mDebugFile;
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -4856,17 +4856,17 @@ public:
       nsTableFrame* tableFrame = static_cast <nsTableFrame*>(mFrame.GetFrame());
       if (tableFrame->NeedToCalcBCBorders()) {
         tableFrame->CalcBCBorders();
       }
     }
     return NS_OK;
   }
 private:
-  AutoWeakFrame mFrame;
+  WeakFrame mFrame;
 };
 
 bool
 nsTableFrame::BCRecalcNeeded(nsStyleContext* aOldStyleContext,
                              nsStyleContext* aNewStyleContext)
 {
   // Attention: the old style context is the one we're forgetting,
   // and hence possibly completely bogus for GetStyle* purposes.
--- a/layout/xul/nsListBoxBodyFrame.cpp
+++ b/layout/xul/nsListBoxBodyFrame.cpp
@@ -1125,25 +1125,25 @@ nsListBoxBodyFrame::GetFirstItemBox(int3
 {
   if (aCreated)
    *aCreated = false;
 
   // Clear ourselves out.
   mBottomFrame = mTopFrame;
 
   if (mTopFrame) {
-    return mTopFrame->IsXULBoxFrame() ? mTopFrame : nullptr;
+    return mTopFrame->IsXULBoxFrame() ? mTopFrame.GetFrame() : nullptr;
   }
 
   // top frame was cleared out
   mTopFrame = GetFirstFrame();
   mBottomFrame = mTopFrame;
 
   if (mTopFrame && mRowsToPrepend <= 0) {
-    return mTopFrame->IsXULBoxFrame() ? mTopFrame : nullptr;
+    return mTopFrame->IsXULBoxFrame() ? mTopFrame.GetFrame() : nullptr;
   }
 
   // At this point, we either have no frames at all, 
   // or the user has scrolled upwards, leaving frames
   // to be created at the top.  Let's determine which
   // content needs a new frame first.
 
   nsCOMPtr<nsIContent> startContent;
@@ -1182,17 +1182,17 @@ nsListBoxBodyFrame::GetFirstItemBox(int3
     fc->CreateListBoxContent(this, nullptr, startContent, &topFrame, isAppend);
     mTopFrame = topFrame;
     if (mTopFrame) {
       if (aCreated)
         *aCreated = true;
 
       mBottomFrame = mTopFrame;
 
-      return mTopFrame->IsXULBoxFrame() ? mTopFrame : nullptr;
+      return mTopFrame->IsXULBoxFrame() ? mTopFrame.GetFrame() : nullptr;
     } else
       return GetFirstItemBox(++aOffset, 0);
   }
 
   return nullptr;
 }
 
 //
--- a/layout/xul/nsListBoxBodyFrame.h
+++ b/layout/xul/nsListBoxBodyFrame.h
@@ -180,17 +180,17 @@ protected:
   void ComputeTotalRowCount();
   int32_t ToRowIndex(nscoord aPos) const;
   void RemoveChildFrame(nsBoxLayoutState &aState, nsIFrame *aChild);
 
   nsTArray< RefPtr<nsPositionChangedEvent> > mPendingPositionChangeEvents;
   nsCOMPtr<nsPIBoxObject> mBoxObject;
 
   // frame markers
-  AutoWeakFrame mTopFrame;
+  WeakFrame mTopFrame;
   nsIFrame* mBottomFrame;
   nsIFrame* mLinkupFrame;
 
   nsListScrollSmoother* mScrollSmoother;
 
   int32_t mRowsToPrepend;
 
   // row height
--- a/layout/xul/nsMenuFrame.cpp
+++ b/layout/xul/nsMenuFrame.cpp
@@ -133,17 +133,17 @@ public:
     else if (mAttr == nsGkAtoms::key) {
       frame->BuildAcceleratorText(true);
     } else if (mAttr == nsGkAtoms::type || mAttr == nsGkAtoms::name) {
       frame->UpdateMenuType();
     }
     return NS_OK;
   }
 protected:
-  AutoWeakFrame       mFrame;
+  WeakFrame         mFrame;
   nsCOMPtr<nsIAtom> mAttr;
 };
 
 //
 // NS_NewMenuFrame and NS_NewMenuItemFrame
 //
 // Wrappers for creating a new menu popup container
 //
--- a/layout/xul/nsProgressMeterFrame.cpp
+++ b/layout/xul/nsProgressMeterFrame.cpp
@@ -26,17 +26,17 @@ class nsReflowFrameRunnable : public moz
 {
 public:
   nsReflowFrameRunnable(nsIFrame* aFrame,
                         nsIPresShell::IntrinsicDirty aIntrinsicDirty,
                         nsFrameState aBitToAdd);
 
   NS_DECL_NSIRUNNABLE
 
-  AutoWeakFrame mWeakFrame;
+  WeakFrame mWeakFrame;
   nsIPresShell::IntrinsicDirty mIntrinsicDirty;
   nsFrameState mBitToAdd;
 };
 
 nsReflowFrameRunnable::nsReflowFrameRunnable(nsIFrame* aFrame,
                           nsIPresShell::IntrinsicDirty aIntrinsicDirty,
                           nsFrameState aBitToAdd)
   : mWeakFrame(aFrame),
@@ -95,17 +95,17 @@ public:
     return shouldFlush;
   }
 
   virtual void ReflowCallbackCanceled() override
   {
     delete this;
   }
 
-  AutoWeakFrame mWeakFrame;
+  WeakFrame mWeakFrame;
 };
 
 NS_IMETHODIMP
 nsProgressMeterFrame::DoXULLayout(nsBoxLayoutState& aState)
 {
   if (mNeedsReflowCallback) {
     nsIReflowCallback* cb = new nsAsyncProgressMeterInit(this);
     if (cb) {
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -182,21 +182,21 @@ public:
         return shouldFlush;
     }
 
     virtual void ReflowCallbackCanceled() override
     {
         delete this;
     }
 
-    AutoWeakFrame mWeakFrame;
+    WeakFrame mWeakFrame;
 };
 
 bool
-nsTextBoxFrame::UpdateAccesskey(AutoWeakFrame& aWeakThis)
+nsTextBoxFrame::UpdateAccesskey(WeakFrame& aWeakThis)
 {
     nsAutoString accesskey;
     nsCOMPtr<nsIDOMXULLabelElement> labelElement = do_QueryInterface(mContent);
     NS_ENSURE_TRUE(aWeakThis.IsAlive(), false);
     if (labelElement) {
         // Accesskey may be stored on control.
         labelElement->GetAccessKey(accesskey);
         NS_ENSURE_TRUE(aWeakThis.IsAlive(), false);
--- a/layout/xul/nsTextBoxFrame.h
+++ b/layout/xul/nsTextBoxFrame.h
@@ -66,17 +66,17 @@ public:
 
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
 
 protected:
   friend class nsAsyncAccesskeyUpdate;
   friend class nsDisplayXULTextBox;
   // Should be called only by nsAsyncAccesskeyUpdate.
   // Returns true if accesskey was updated.
-  bool UpdateAccesskey(AutoWeakFrame& aWeakThis);
+  bool UpdateAccesskey(WeakFrame& aWeakThis);
   void UpdateAccessTitle();
   void UpdateAccessIndex();
 
   // Recompute our title, ignoring the access key but taking into
   // account text-transform.
   void RecomputeTitle();
 
   // REVIEW: SORRY! Couldn't resist devirtualizing these
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -1258,22 +1258,21 @@ nsXULPopupManager::HidePopupAfterDelay(n
   // is set to mTimerMenu, so it should be safe to keep a reference to it
   mTimerMenu = aPopup;
 }
 
 void
 nsXULPopupManager::HidePopupsInList(const nsTArray<nsMenuPopupFrame *> &aFrames)
 {
   // Create a weak frame list. This is done in a separate array with the
-  // right capacity predetermined, otherwise the array would get resized and
-  // move the weak frame pointers around.
-  nsTArray<AutoWeakFrame> weakPopups(aFrames.Length());
+  // right capacity predetermined to avoid multiple allocations.
+  nsTArray<WeakFrame> weakPopups(aFrames.Length());
   uint32_t f;
   for (f = 0; f < aFrames.Length(); f++) {
-    AutoWeakFrame* wframe = weakPopups.AppendElement();
+    WeakFrame* wframe = weakPopups.AppendElement();
     if (wframe)
       *wframe = aFrames[f];
   }
 
   for (f = 0; f < weakPopups.Length(); f++) {
     // check to ensure that the frame is still alive before hiding it.
     if (weakPopups[f].IsAlive()) {
       nsMenuPopupFrame* frame =
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -4901,17 +4901,17 @@ public:
     if (mFrame.IsAlive()) {
       nsTreeBodyFrame* tree = static_cast<nsTreeBodyFrame*>(mFrame.GetFrame());
       nsTreeBodyFrame::ScrollParts parts = tree->GetScrollParts();
       tree->CheckOverflow(parts);
     }
     return NS_OK;
   }
 private:
-  AutoWeakFrame mFrame;
+  WeakFrame mFrame;
 };
 
 bool
 nsTreeBodyFrame::FullScrollbarsUpdate(bool aNeedsFullInvalidation)
 {
   ScrollParts parts = GetScrollParts();
   AutoWeakFrame weakFrame(this);
   AutoWeakFrame weakColumnsFrame(parts.mColumnsFrame);