Bug 1374112 part 3 - Use AllocateFCItem/FreeFCItem exclusively for allocating FrameConstructionItems. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Mon, 11 Sep 2017 00:27:12 +0200
changeset 429503 9dcca3ac0aaa19800a3f0c6a7c4ead1d9dfa14d8
parent 429502 8bc4d3b25dfb1f7092b6bfd471ff94f88e2ca573
child 429504 9b2a93197d2ba3a04d05644c55f3432c2dba5866
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1374112
milestone57.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 1374112 part 3 - Use AllocateFCItem/FreeFCItem exclusively for allocating FrameConstructionItems. r=dholbert MozReview-Commit-ID: 7TqWZeTV91J
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2681,20 +2681,20 @@ nsCSSFrameConstructor::ConstructDocEleme
     // XXXbz on the other hand, if we converted this whole function to
     // FrameConstructionData/Item, then we'd need the right function
     // here... but would probably be able to get away with less code in this
     // function in general.
     // Use a null PendingBinding, since our binding is not in fact pending.
     static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
     already_AddRefed<nsStyleContext> extraRef =
       RefPtr<nsStyleContext>(styleContext).forget();
-    FrameConstructionItem item(&rootSVGData, aDocElement,
-                               aDocElement->NodeInfo()->NameAtom(),
-                               kNameSpaceID_SVG, nullptr, extraRef, true,
-                               nullptr);
+    AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
+                                   aDocElement->NodeInfo()->NameAtom(),
+                                   kNameSpaceID_SVG, nullptr, extraRef, true,
+                                   nullptr);
 
     nsFrameItems frameItems;
     contentFrame = static_cast<nsContainerFrame*>(
       ConstructOuterSVG(state, item, mDocElementContainingBlock,
                         styleContext->StyleDisplay(),
                         frameItems));
     newFrame = frameItems.FirstChild();
     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
@@ -2731,20 +2731,20 @@ nsCSSFrameConstructor::ConstructDocEleme
     // XXXbz on the other hand, if we converted this whole function to
     // FrameConstructionData/Item, then we'd need the right function
     // here... but would probably be able to get away with less code in this
     // function in general.
     // Use a null PendingBinding, since our binding is not in fact pending.
     static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
     already_AddRefed<nsStyleContext> extraRef =
       RefPtr<nsStyleContext>(styleContext).forget();
-    FrameConstructionItem item(&rootTableData, aDocElement,
-                               aDocElement->NodeInfo()->NameAtom(),
-                               kNameSpaceID_None, nullptr, extraRef, true,
-                               nullptr);
+    AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
+                                   aDocElement->NodeInfo()->NameAtom(),
+                                   kNameSpaceID_None, nullptr, extraRef, true,
+                                   nullptr);
 
     nsFrameItems frameItems;
     // if the document is a table then just populate it.
     contentFrame = static_cast<nsContainerFrame*>(
       ConstructTable(state, item, mDocElementContainingBlock,
                      styleContext->StyleDisplay(),
                      frameItems));
     newFrame = frameItems.FirstChild();
@@ -3070,17 +3070,17 @@ nsCSSFrameConstructor::ConstructAnonymou
   NS_ASSERTION(aFrame->IsCanvasFrame(), "aFrame should be canvas frame!");
 
   AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
   GetAnonymousContent(aDocElement, aFrame, anonymousItems);
   if (anonymousItems.IsEmpty()) {
     return;
   }
 
-  FrameConstructionItemList itemsToConstruct;
+  AutoFrameConstructionItemList itemsToConstruct(this);
   nsContainerFrame* frameAsContainer = do_QueryFrame(aFrame);
   AddFCItemsForAnonymousContent(aState, frameAsContainer, anonymousItems, itemsToConstruct);
 
   nsFrameItems frameItems;
   ConstructFramesFromItemList(aState, itemsToConstruct, frameAsContainer,
                               /* aParentIsWrapperAnonBox = */ false,
                               frameItems);
   frameAsContainer->AppendFrames(kPrincipalList, frameItems);
@@ -3279,17 +3279,17 @@ nsCSSFrameConstructor::ConstructSelectFr
     MOZ_ASSERT(newAnonymousItems[0].mContent == comboboxFrame->GetDisplayNode());
     newAnonymousItems.RemoveElementAt(0);
     nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
     MOZ_ASSERT(customFrame);
     customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
     childItems.AddChild(customFrame);
 
     // The other piece of NAC can take the normal path.
-    FrameConstructionItemList fcItems;
+    AutoFrameConstructionItemList fcItems(this);
     AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
                                   fcItems);
     ConstructFramesFromItemList(aState, fcItems, comboboxFrame,
                                 /* aParentIsWrapperAnonBox = */ false,
                                 childItems);
 
     comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
 
@@ -4720,17 +4720,17 @@ nsCSSFrameConstructor::BeginBuildingScro
   if (scrollNAC.Length() > 0) {
     TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
     if (aState.HasAncestorFilter()) {
       ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
     } else {
       ancestorPusher.PushStyleScope(aContent->AsElement());
     }
 
-    FrameConstructionItemList items;
+    AutoFrameConstructionItemList items(this);
     AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items);
     ConstructFramesFromItemList(aState, items, gfxScrollFrame,
                                 /* aParentIsWrapperAnonBox = */ false,
                                 anonymousItems);
   }
 
   aNewFrame = gfxScrollFrame;
   gfxScrollFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
@@ -5747,17 +5747,17 @@ nsCSSFrameConstructor::AddPageBreakItem(
   MOZ_ASSERT(pseudoStyle->StyleDisplay()->mDisplay == StyleDisplay::Block,
              "Unexpected display");
 
   static const FrameConstructionData sPageBreakData =
     FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame);
 
   // Lie about the tag and namespace so we don't trigger anything
   // interesting during frame construction.
-  aItems.AppendItem(&sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak,
+  aItems.AppendItem(this, &sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak,
                     kNameSpaceID_None, nullptr, pseudoStyle.forget(),
                     true, nullptr);
 }
 
 bool
 nsCSSFrameConstructor::ShouldCreateItemsForChild(nsFrameConstructorState& aState,
                                                  nsIContent* aContent,
                                                  nsContainerFrame* aParentFrame)
@@ -6165,24 +6165,24 @@ nsCSSFrameConstructor::AddFrameConstruct
   }
 
   FrameConstructionItem* item = nullptr;
   if (details && details->Open()) {
     auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
     if (summary && summary->IsMainSummary()) {
       // If details is open, the main summary needs to be rendered as if it is
       // the first child, so add the item to the front of the item list.
-      item = aItems.PrependItem(data, aContent, aTag, aNameSpaceID,
+      item = aItems.PrependItem(this, data, aContent, aTag, aNameSpaceID,
                                 pendingBinding, styleContext.forget(),
                                 aSuppressWhiteSpaceOptimizations, aAnonChildren);
     }
   }
 
   if (!item) {
-    item = aItems.AppendItem(data, aContent, aTag, aNameSpaceID,
+    item = aItems.AppendItem(this, data, aContent, aTag, aNameSpaceID,
                              pendingBinding, styleContext.forget(),
                              aSuppressWhiteSpaceOptimizations, aAnonChildren);
   }
   item->mIsText = isText;
   item->mIsGeneratedContent = isGeneratedContent;
   item->mIsAnonymousContentCreatorContent =
     aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
   if (isGeneratedContent) {
@@ -7792,17 +7792,17 @@ nsCSSFrameConstructor::ContentAppended(n
                                 GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
                                 GetAbsoluteContainingBlock(parentFrame, ABS_POS),
                                 containingBlock);
 
   LayoutFrameType frameType = parentFrame->Type();
 
   FlattenedChildIterator iter(aContainer);
   bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
-  FrameConstructionItemList items;
+  AutoFrameConstructionItemList items(this);
   if (aFirstNewContent->GetPreviousSibling() &&
       GetParentType(frameType) == eTypeBlock &&
       haveNoXBLChildren) {
     // If there's a text node in the normal content list just before the new
     // items, and it has no frame, make a frame construction item for it. If it
     // doesn't need a frame, ConstructFramesFromItemList below won't give it
     // one.  No need to do all this if our parent type is not block, though,
     // since WipeContainingBlock already handles that situation.
@@ -8363,17 +8363,17 @@ nsCSSFrameConstructor::ContentRangeInser
       // Insert the new frames after the last continuation of the :before
       prevSibling = firstChild->GetTailContinuation();
       insertion.mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
       // Don't change isAppend here; we'll can call AppendFrames as needed, and
       // the change to our prevSibling doesn't affect that.
     }
   }
 
-  FrameConstructionItemList items;
+  AutoFrameConstructionItemList items(this);
   ParentType parentType = GetParentType(frameType);
   FlattenedChildIterator iter(aContainer);
   bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
   if (aStartChild->GetPreviousSibling() &&
       parentType == eTypeBlock && haveNoXBLChildren) {
     // If there's a text node in the normal content list just before the
     // new nodes, and it has no frame, make a frame construction item for
     // it, because it might need a frame now.  No need to do this if our
@@ -9499,17 +9499,17 @@ nsCSSFrameConstructor::ReplicateFixedFra
     nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
     if (prevPlaceholder &&
         nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
       // We want to use the same style as the primary style frame for
       // our content
       nsIContent* content = fixed->GetContent();
       nsStyleContext* styleContext =
         nsLayoutUtils::GetStyleFrame(content)->StyleContext();
-      FrameConstructionItemList items;
+      AutoFrameConstructionItemList items(this);
       AddFrameConstructionItemsInternal(state, content, canvasFrame,
                                         content->NodeInfo()->NameAtom(),
                                         content->GetNameSpaceID(),
                                         true,
                                         styleContext,
                                         ITEM_ALLOW_XBL_BASE |
                                           ITEM_ALLOW_PAGE_BREAK,
                                         nullptr, items);
@@ -10299,17 +10299,17 @@ nsCSSFrameConstructor::CreateNeededAnonF
       bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
       bool nextChildNeedsAnonItem =
         !hitEnd &&
         afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox);
 
       if (!nextChildNeedsAnonItem) {
         // There's nothing after the whitespace that we need to wrap, so we
         // just drop this run of whitespace.
-        iter.DeleteItemsTo(afterWhitespaceIter);
+        iter.DeleteItemsTo(this, afterWhitespaceIter);
         if (hitEnd) {
           // Nothing left to do -- we're finished!
           return;
         }
         // else, we have a next child and it does not want to be wrapped.  So,
         // we jump back to the beginning of the loop to skip over that child
         // (and anything else non-wrappable after it)
         MOZ_ASSERT(!iter.IsDone() &&
@@ -10341,17 +10341,17 @@ nsCSSFrameConstructor::CreateNeededAnonF
 
     static const FrameConstructionData sBlockFormattingContextFCData =
       FCDATA_DECL(FCDATA_SKIP_FRAMESET |
                   FCDATA_USE_CHILD_ITEMS |
                   FCDATA_IS_WRAPPER_ANON_BOX,
                   NS_NewBlockFormattingContext);
 
     FrameConstructionItem* newItem =
-      new FrameConstructionItem(&sBlockFormattingContextFCData,
+      new (this) FrameConstructionItem(&sBlockFormattingContextFCData,
                                 // Use the content of our parent frame
                                 parentContent,
                                 // Lie about the tag; it doesn't matter anyway
                                 pseudoType,
                                 iter.item().mNameSpaceID,
                                 // no pending binding
                                 nullptr,
                                 wrapperStyle,
@@ -10372,17 +10372,17 @@ nsCSSFrameConstructor::CreateNeededAnonF
     newItem->mChildItems.SetLineBoundaryAtEnd(true);
     // The parent of the items in aItems is also the parent of the items
     // in mChildItems
     newItem->mChildItems.SetParentHasNoXBLChildren(
       aItems.ParentHasNoXBLChildren());
 
     // Eat up all items between |iter| and |endIter| and put them in our
     // wrapper. This advances |iter| to point to |endIter|.
-    iter.AppendItemsToList(endIter, newItem->mChildItems);
+    iter.AppendItemsToList(this, endIter, newItem->mChildItems);
 
     iter.InsertItem(newItem);
   } while (!iter.IsDone());
 }
 
 /* static */ nsCSSFrameConstructor::RubyWhitespaceType
 nsCSSFrameConstructor::ComputeRubyWhitespaceType(StyleDisplay aPrevDisplay,
                                                  StyleDisplay aNextDisplay)
@@ -10505,17 +10505,17 @@ nsCSSFrameConstructor::WrapItemsInPseudo
     // trailing whitespace described in the spec have been trimmed at
     // this point. With this precondition, it is safe not to check
     // whether contentEndIter has been done.
     RubyWhitespaceType whitespaceType =
       InterpretRubyWhitespace(aState, endIter, contentEndIter);
     if (whitespaceType == eRubyInterLevelWhitespace) {
       // Remove inter-level whitespace.
       bool atStart = (aIter == endIter);
-      endIter.DeleteItemsTo(contentEndIter);
+      endIter.DeleteItemsTo(this, contentEndIter);
       if (atStart) {
         aIter = endIter;
       }
     } else if (whitespaceType == eRubyInterSegmentWhitespace) {
       // If this level container starts with inter-segment whitespaces,
       // wrap them. Break at contentEndIter. Otherwise, leave it here.
       // Break at endIter. They will be wrapped when we are here again.
       if (aIter == endIter) {
@@ -10554,33 +10554,33 @@ nsCSSFrameConstructor::TrimLeadingAndTra
     nsFrameConstructorState& aState,
     FrameConstructionItemList& aItems)
 {
   FCItemIterator iter(aItems);
   if (!iter.IsDone() &&
       iter.item().IsWhitespace(aState)) {
     FCItemIterator spaceEndIter(iter);
     spaceEndIter.SkipWhitespace(aState);
-    iter.DeleteItemsTo(spaceEndIter);
+    iter.DeleteItemsTo(this, spaceEndIter);
   }
 
   iter.SetToEnd();
   if (!iter.AtStart()) {
     FCItemIterator spaceEndIter(iter);
     do {
       iter.Prev();
       if (iter.AtStart()) {
         // It's fine to not check the first item, because we
         // should have trimmed leading whitespaces above.
         break;
       }
     } while (iter.item().IsWhitespace(aState));
     iter.Next();
     if (iter != spaceEndIter) {
-      iter.DeleteItemsTo(spaceEndIter);
+      iter.DeleteItemsTo(this, spaceEndIter);
     }
   }
 }
 
 /**
  * This function walks through the child list (aItems) and creates
  * needed pseudo ruby boxes to wrap misparented children.
  */
@@ -10701,17 +10701,17 @@ nsCSSFrameConstructor::CreateNeededPseud
           //    tabular container according to rule 1.3 of CSS 2.1 Sec 17.2.1.
           //    (Being a tabular container pretty much means ourParentType is
           //    not eTypeBlock besides the eTypeColGroup case, which won't
           //    reach here.)
           if ((!trailingSpaces &&
                IsTableParentType(spaceEndIter.item().DesiredParentType())) ||
               (trailingSpaces && ourParentType != eTypeBlock)) {
             bool updateStart = (iter == endIter);
-            endIter.DeleteItemsTo(spaceEndIter);
+            endIter.DeleteItemsTo(this, spaceEndIter);
             NS_ASSERTION(trailingSpaces == endIter.IsDone(),
                          "These should match");
 
             if (updateStart) {
               iter = endIter;
             }
 
             if (trailingSpaces) {
@@ -10846,17 +10846,17 @@ nsCSSFrameConstructor::WrapItemsInPseudo
       mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
                                                                  aParentStyle);
   } else {
     wrapperStyle =
       mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(pseudoType);
   }
 
   FrameConstructionItem* newItem =
-    new FrameConstructionItem(&pseudoData.mFCData,
+    new (this) FrameConstructionItem(&pseudoData.mFCData,
                               // Use the content of our parent frame
                               aParentContent,
                               // Lie about the tag; it doesn't matter anyway
                               pseudoType,
                               // The namespace does matter, however; it needs
                               // to match that of our first child item to
                               // match the old behavior
                               aIter.item().mNameSpaceID,
@@ -10887,17 +10887,17 @@ nsCSSFrameConstructor::WrapItemsInPseudo
   }
   // The parent of the items in aItems is also the parent of the items
   // in mChildItems
   newItem->mChildItems.SetParentHasNoXBLChildren(
       aIter.List()->ParentHasNoXBLChildren());
 
   // Eat up all items between |aIter| and |aEndIter| and put them in our
   // wrapper Advances |aIter| to point to |aEndIter|.
-  aIter.AppendItemsToList(aEndIter, newItem->mChildItems);
+  aIter.AppendItemsToList(this, aEndIter, newItem->mChildItems);
 
   aIter.InsertItem(newItem);
 }
 
 void
 nsCSSFrameConstructor::CreateNeededPseudoSiblings(
     nsFrameConstructorState& aState,
     FrameConstructionItemList& aItems,
@@ -10917,27 +10917,27 @@ nsCSSFrameConstructor::CreateNeededPseud
                "Child of ruby frame should either a rbc or a rtc");
 
   const PseudoParentData& pseudoData =
     sPseudoParentData[eTypeRubyBaseContainer];
   already_AddRefed<nsStyleContext> pseudoStyle = mPresShell->StyleSet()->
     ResolveInheritingAnonymousBoxStyle(*pseudoData.mPseudoType,
                                        aParentFrame->StyleContext());
   FrameConstructionItem* newItem =
-    new FrameConstructionItem(&pseudoData.mFCData,
-                              // Use the content of the parent frame
-                              aParentFrame->GetContent(),
-                              // Tag type
-                              *pseudoData.mPseudoType,
-                              // Use the namespace of the rtc frame
-                              iter.item().mNameSpaceID,
-                              // no pending binding
-                              nullptr,
-                              pseudoStyle,
-                              true, nullptr);
+    new (this) FrameConstructionItem(&pseudoData.mFCData,
+                                     // Use the content of the parent frame
+                                     aParentFrame->GetContent(),
+                                     // Tag type
+                                     *pseudoData.mPseudoType,
+                                     // Use the namespace of the rtc frame
+                                     iter.item().mNameSpaceID,
+                                     // no pending binding
+                                     nullptr,
+                                     pseudoStyle,
+                                     true, nullptr);
   newItem->mIsAllInline = true;
   newItem->mChildItems.SetParentHasNoXBLChildren(true);
   iter.InsertItem(newItem);
 }
 
 #ifdef DEBUG
 /**
  * Returns true iff aFrame should be wrapped in an anonymous flex/grid item,
@@ -11233,17 +11233,17 @@ nsCSSFrameConstructor::ProcessChildren(n
     aState.PushFloatContainingBlock(nullptr, floatSaveState);
   } else if (aFrame->IsFloatContainingBlock()) {
     aState.PushFloatContainingBlock(aFrame, floatSaveState);
   }
 
   nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
                                                            aPendingBinding);
 
-  FrameConstructionItemList itemsToConstruct;
+  AutoFrameConstructionItemList itemsToConstruct(this);
 
   // If we have first-letter or first-line style then frames can get
   // moved around so don't set these flags.
   if (aAllowBlockStyles && !haveFirstLetterStyle && !haveFirstLineStyle) {
     itemsToConstruct.SetLineBoundaryAtStart(true);
     itemsToConstruct.SetLineBoundaryAtEnd(true);
   }
 
@@ -12311,17 +12311,17 @@ nsCSSFrameConstructor::CreateListBoxCont
 
     if (StyleDisplay::None == display->mDisplay) {
       *aNewFrame = nullptr;
       return;
     }
 
     BeginUpdate();
 
-    FrameConstructionItemList items;
+    AutoFrameConstructionItemList items(this);
     AddFrameConstructionItemsInternal(state, aChild, aParentFrame,
                                       aChild->NodeInfo()->NameAtom(),
                                       aChild->GetNameSpaceID(),
                                       true, styleContext,
                                       ITEM_ALLOW_XBL_BASE, nullptr, items);
     ConstructFramesFromItemList(state, items, aParentFrame,
                                 /* aParentIsWrapperAnonBox = */ false,
                                 frameItems);
@@ -12986,17 +12986,17 @@ nsCSSFrameConstructor::WipeContainingBlo
             NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
           }
 #endif
         } else {
           okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
         }
 
         if (okToDrop) {
-          iter.DeleteItemsTo(spaceEndIter);
+          iter.DeleteItemsTo(this, spaceEndIter);
         } else {
           // We're done: we don't want to drop the whitespace, and it has the
           // wrong parent type.
           break;
         }
 
         // Now loop, since |iter| points to item right after the whitespace we
         // removed.
@@ -13379,17 +13379,17 @@ Iterator::AppendItemToList(FrameConstruc
   aTargetList.mItems.insertBack(item);
 
   mList.AdjustCountsForItem(item, -1);
   aTargetList.AdjustCountsForItem(item, 1);
 }
 
 void
 nsCSSFrameConstructor::FrameConstructionItemList::
-Iterator::AppendItemsToList(const Iterator& aEnd,
+Iterator::AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
                             FrameConstructionItemList& aTargetList)
 {
   NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
   NS_PRECONDITION(&mList == &aEnd.mList, "End iterator for some other list?");
 
   // We can't just move our guts to the other list if it already has
   // some information or if we're not moving our entire list.
   if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() ||
@@ -13410,18 +13410,17 @@ Iterator::AppendItemsToList(const Iterat
   aTargetList.mItemCount = mList.mItemCount;
   memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
          sizeof(aTargetList.mDesiredParentCounts));
 
   // Swap out undisplayed item arrays, before we nuke the array on our end
   aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems);
 
   // reset mList
-  mList.~FrameConstructionItemList();
-  new (&mList) FrameConstructionItemList();
+  mList.Reset(aFCtor);
 
   // Point ourselves to aEnd, as advertised
   SetToEnd();
   NS_POSTCONDITION(*this == aEnd, "How did that happen?");
 }
 
 void
 nsCSSFrameConstructor::FrameConstructionItemList::
@@ -13435,28 +13434,28 @@ Iterator::InsertItem(FrameConstructionIt
   }
   mList.AdjustCountsForItem(aItem, 1);
 
   NS_POSTCONDITION(aItem->getNext() == mCurrent, "How did that happen?");
 }
 
 void
 nsCSSFrameConstructor::FrameConstructionItemList::
-Iterator::DeleteItemsTo(const Iterator& aEnd)
+Iterator::DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd)
 {
   NS_PRECONDITION(&mList == &aEnd.mList, "End iterator for some other list?");
   NS_PRECONDITION(*this != aEnd, "Shouldn't be at aEnd yet");
 
   do {
     NS_ASSERTION(!IsDone(), "Ran off end of list?");
     FrameConstructionItem* item = mCurrent;
     Next();
     item->remove();
     mList.AdjustCountsForItem(item, -1);
-    delete item;
+    item->Delete(aFCtor);
   } while (*this != aEnd);
 }
 
 void
 nsCSSFrameConstructor::QuotesDirty()
 {
   NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news");
   mQuotesDirty = true;
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -835,50 +835,27 @@ private:
      match or if the matching tag has a FrameConstructionDataGetter that
      returns null. */
   static const FrameConstructionData*
     FindDataByTag(nsIAtom* aTag, Element* aElement,
                   nsStyleContext* aStyleContext,
                   const FrameConstructionDataByTag* aDataPtr,
                   uint32_t aDataLength);
 
-  /* A class representing a list of FrameConstructionItems */
-  class FrameConstructionItemList final {
+  /* A class representing a list of FrameConstructionItems.  Instances of this
+     class are only created as AutoFrameConstructionItemList, or as a member
+     of FrameConstructionItem. */
+  class FrameConstructionItemList
+  {
   public:
-    FrameConstructionItemList() :
-      mInlineCount(0),
-      mBlockCount(0),
-      mLineParticipantCount(0),
-      mItemCount(0),
-      mLineBoundaryAtStart(false),
-      mLineBoundaryAtEnd(false),
-      mParentHasNoXBLChildren(false),
-      mTriedConstructingFrames(false)
+    void Reset(nsCSSFrameConstructor* aFCtor)
     {
-      memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
-    }
-
-    ~FrameConstructionItemList() {
-      while (FrameConstructionItem* item = mItems.popFirst()) {
-        delete item;
-      }
-
-      // Create the undisplayed entries for our mUndisplayedItems, if any, but
-      // only if we have tried constructing frames for this item list.  If we
-      // haven't, then we're just throwing it away and will probably try again.
-      if (!mUndisplayedItems.IsEmpty() && mTriedConstructingFrames) {
-        // We could store the frame manager in a member, but just
-        // getting it off the style context is not too bad.
-        nsFrameManager *mgr =
-          mUndisplayedItems[0].mStyleContext->PresContext()->FrameManager();
-        for (uint32_t i = 0; i < mUndisplayedItems.Length(); ++i) {
-          UndisplayedItem& item = mUndisplayedItems[i];
-          mgr->RegisterDisplayNoneStyleFor(item.mContent, item.mStyleContext);
-        }
-      }
+      Destroy(aFCtor);
+      this->~FrameConstructionItemList();
+      new (this) FrameConstructionItemList();
     }
 
     void SetLineBoundaryAtStart(bool aBoundary) { mLineBoundaryAtStart = aBoundary; }
     void SetLineBoundaryAtEnd(bool aBoundary) { mLineBoundaryAtEnd = aBoundary; }
     void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) {
       mParentHasNoXBLChildren = aHasNoXBLChildren;
     }
     void SetTriedConstructingFrames() { mTriedConstructingFrames = true; }
@@ -892,51 +869,53 @@ private:
     bool AllWantParentType(ParentType aDesiredParentType) const {
       return mDesiredParentCounts[aDesiredParentType] == mItemCount;
     }
 
     // aSuppressWhiteSpaceOptimizations is true if optimizations that
     // skip constructing whitespace frames for this item or items
     // around it cannot be performed.
     // Also, the return value is always non-null, thanks to infallible 'new'.
-    FrameConstructionItem* AppendItem(const FrameConstructionData* aFCData,
+    FrameConstructionItem* AppendItem(nsCSSFrameConstructor* aFCtor,
+                                      const FrameConstructionData* aFCData,
                                       nsIContent* aContent,
                                       nsIAtom* aTag,
                                       int32_t aNameSpaceID,
                                       PendingBinding* aPendingBinding,
                                       already_AddRefed<nsStyleContext>&& aStyleContext,
                                       bool aSuppressWhiteSpaceOptimizations,
                                       nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren)
     {
       FrameConstructionItem* item =
-        new FrameConstructionItem(aFCData, aContent, aTag, aNameSpaceID,
-                                  aPendingBinding, aStyleContext,
-                                  aSuppressWhiteSpaceOptimizations,
-                                  aAnonChildren);
+        new (aFCtor) FrameConstructionItem(aFCData, aContent, aTag, aNameSpaceID,
+                                           aPendingBinding, aStyleContext,
+                                           aSuppressWhiteSpaceOptimizations,
+                                           aAnonChildren);
       mItems.insertBack(item);
       ++mItemCount;
       ++mDesiredParentCounts[item->DesiredParentType()];
       return item;
     }
 
     // Arguments are the same as AppendItem().
-    FrameConstructionItem* PrependItem(const FrameConstructionData* aFCData,
+    FrameConstructionItem* PrependItem(nsCSSFrameConstructor* aFCtor,
+                                       const FrameConstructionData* aFCData,
                                        nsIContent* aContent,
                                        nsIAtom* aTag,
                                        int32_t aNameSpaceID,
                                        PendingBinding* aPendingBinding,
                                        already_AddRefed<nsStyleContext>&& aStyleContext,
                                        bool aSuppressWhiteSpaceOptimizations,
                                        nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren)
     {
       FrameConstructionItem* item =
-        new FrameConstructionItem(aFCData, aContent, aTag, aNameSpaceID,
-                                  aPendingBinding, aStyleContext,
-                                  aSuppressWhiteSpaceOptimizations,
-                                  aAnonChildren);
+        new (aFCtor) FrameConstructionItem(aFCData, aContent, aTag, aNameSpaceID,
+                                           aPendingBinding, aStyleContext,
+                                           aSuppressWhiteSpaceOptimizations,
+                                           aAnonChildren);
       mItems.insertFront(item);
       ++mItemCount;
       ++mDesiredParentCounts[item->DesiredParentType()];
       return item;
     }
 
     void AppendUndisplayedItem(nsIContent* aContent,
                                nsStyleContext* aStyleContext) {
@@ -1038,39 +1017,91 @@ private:
       void AppendItemToList(FrameConstructionItemList& aTargetList);
 
       // As above, but moves all items starting with this iterator until we
       // get to aEnd; the item pointed to by aEnd is not stolen.  This method
       // might have optimizations over just looping and doing StealItem for
       // some special cases.  After this method returns, this iterator will
       // point to the item aEnd points to now; aEnd is not modified.
       // aTargetList must not be the list this iterator is iterating over.
-      void AppendItemsToList(const Iterator& aEnd,
+      void AppendItemsToList(nsCSSFrameConstructor*     aFCtor,
+                             const Iterator&            aEnd,
                              FrameConstructionItemList& aTargetList);
 
       // Insert aItem in this iterator's list right before the item pointed to
       // by this iterator.  After the insertion, this iterator will continue to
       // point to the item it now points to (the one just after the
       // newly-inserted item).  This iterator is allowed to be done; in that
       // case this call just appends the given item to the list.
       void InsertItem(FrameConstructionItem* aItem);
 
       // Delete the items between this iterator and aEnd, including the item
       // this iterator currently points to but not including the item pointed
       // to by aEnd.  When this returns, this iterator will point to the same
       // item as aEnd.  This iterator must not equal aEnd when this method is
       // called.
-      void DeleteItemsTo(const Iterator& aEnd);
+      void DeleteItemsTo(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd);
 
     private:
       FrameConstructionItem* mCurrent;
       FrameConstructionItemList& mList;
     };
 
+  protected:
+    FrameConstructionItemList() :
+      mInlineCount(0),
+      mBlockCount(0),
+      mLineParticipantCount(0),
+      mItemCount(0),
+      mLineBoundaryAtStart(false),
+      mLineBoundaryAtEnd(false),
+      mParentHasNoXBLChildren(false),
+      mTriedConstructingFrames(false)
+    {
+      MOZ_COUNT_CTOR(FrameConstructionItemList);
+      memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
+    }
+
+    void Destroy(nsCSSFrameConstructor* aFCtor)
+    {
+      while (FrameConstructionItem* item = mItems.popFirst()) {
+        item->Delete(aFCtor);
+      }
+
+      // Create the undisplayed entries for our mUndisplayedItems, if any, but
+      // only if we have tried constructing frames for this item list.  If we
+      // haven't, then we're just throwing it away and will probably try again.
+      if (!mUndisplayedItems.IsEmpty() && mTriedConstructingFrames) {
+        for (uint32_t i = 0; i < mUndisplayedItems.Length(); ++i) {
+          UndisplayedItem& item = mUndisplayedItems[i];
+          aFCtor->RegisterDisplayNoneStyleFor(item.mContent, item.mStyleContext);
+        }
+      }
+    }
+
+    // Prevent stack instances (except as AutoFrameConstructionItemList).
+    friend struct FrameConstructionItem;
+    ~FrameConstructionItemList()
+    {
+      MOZ_COUNT_DTOR(FrameConstructionItemList);
+      MOZ_ASSERT(mItems.isEmpty(), "leaking");
+    }
   private:
+    // Not allocated from the heap!
+    void* operator new(size_t) = delete;
+    void* operator new[](size_t) = delete;
+#ifdef _MSC_VER  /* Visual Studio */
+    void operator delete(void*) { MOZ_CRASH("FrameConstructionItemList::del"); }
+#else
+    void operator delete(void*) = delete;
+#endif
+    void operator delete[](void*) = delete;
+    // Placement new is used by Reset().
+    void* operator new(size_t, void* aPtr) { return aPtr; }
+
     struct UndisplayedItem {
       UndisplayedItem(nsIContent* aContent, nsStyleContext* aStyleContext) :
         mContent(aContent), mStyleContext(aStyleContext)
       {}
 
       nsIContent * const mContent;
       RefPtr<nsStyleContext> mStyleContext;
     };
@@ -1093,22 +1124,37 @@ private:
     // frames created by these items
     bool mLineBoundaryAtEnd;
     // True if the parent is guaranteed to have no XBL anonymous children
     bool mParentHasNoXBLChildren;
     // True if we have tried constructing frames from this list
     bool mTriedConstructingFrames;
   };
 
+  /* A struct representing a list of FrameConstructionItems on the stack. */
+  struct MOZ_RAII AutoFrameConstructionItemList final
+    : public FrameConstructionItemList
+  {
+    template<typename... Args>
+    explicit AutoFrameConstructionItemList(nsCSSFrameConstructor* aFCtor, Args&&... args)
+      : FrameConstructionItemList(std::forward<Args>(args)...)
+      , mFCtor(aFCtor)
+    { MOZ_ASSERT(mFCtor); }
+    ~AutoFrameConstructionItemList() { Destroy(mFCtor); }
+  private:
+    nsCSSFrameConstructor* const mFCtor;
+  };
+
   typedef FrameConstructionItemList::Iterator FCItemIterator;
 
   /* A struct representing an item for which frames might need to be
    * constructed.  This contains all the information needed to construct the
    * frame other than the parent frame and whatever would be stored in the
-   * frame constructor state. */
+   * frame constructor state.  You probably want to use
+   * AutoFrameConstructionItem instead of this struct. */
   struct FrameConstructionItem final
     : public mozilla::LinkedListElement<FrameConstructionItem> {
     FrameConstructionItem(const FrameConstructionData* aFCData,
                           nsIContent* aContent,
                           nsIAtom* aTag,
                           int32_t aNameSpaceID,
                           PendingBinding* aPendingBinding,
                           already_AddRefed<nsStyleContext>& aStyleContext,
@@ -1119,33 +1165,42 @@ private:
       mNameSpaceID(aNameSpaceID),
       mSuppressWhiteSpaceOptimizations(aSuppressWhiteSpaceOptimizations),
       mIsText(false), mIsGeneratedContent(false),
       mIsAnonymousContentCreatorContent(false),
       mIsRootPopupgroup(false), mIsAllInline(false), mIsBlock(false),
       mHasInlineEnds(false), mIsPopup(false),
       mIsLineParticipant(false), mIsForSVGAElement(false)
     {
+      MOZ_COUNT_CTOR(FrameConstructionItem);
       if (aAnonChildren) {
         NS_ASSERTION(!(mFCData->mBits & FCDATA_FUNC_IS_FULL_CTOR) ||
                      mFCData->mFullConstructor ==
                        &nsCSSFrameConstructor::ConstructInline,
                      "This is going to fail");
         NS_ASSERTION(!(mFCData->mBits & FCDATA_USE_CHILD_ITEMS),
                      "nsIAnonymousContentCreator::CreateAnonymousContent "
                      "implementations should not output a list where the "
                      "items have children in this case");
         mAnonChildren.SwapElements(*aAnonChildren);
       }
     }
-    ~FrameConstructionItem() {
+
+    void* operator new(size_t, nsCSSFrameConstructor* aFCtor)
+    { return aFCtor->AllocateFCItem(); }
+
+    void Delete(nsCSSFrameConstructor* aFCtor)
+    {
+      mChildItems.Destroy(aFCtor);
       if (mIsGeneratedContent) {
         mContent->UnbindFromTree();
         NS_RELEASE(mContent);
       }
+      this->~FrameConstructionItem();
+      aFCtor->FreeFCItem(this);
     }
 
     ParentType DesiredParentType() {
       return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
     }
 
     // Indicates whether (when in a flex or grid container) this item needs
     // to be wrapped in an anonymous block.  (Note that we implement
@@ -1234,17 +1289,54 @@ private:
     // go into the global popup items.
     bool mIsPopup:1;
     // Whether this item should be treated as a line participant
     bool mIsLineParticipant:1;
     // Whether this item is for an SVG <a> element
     bool mIsForSVGAElement:1;
 
   private:
+    // Not allocated from the general heap - instead, use the new/Delete APIs
+    // that take a nsCSSFrameConstructor* (which manages our arena allocation).
+    void* operator new(size_t) = delete;
+    void* operator new[](size_t) = delete;
+#ifdef _MSC_VER  /* Visual Studio */
+    void operator delete(void*) { MOZ_CRASH("FrameConstructionItem::delete"); }
+#else
+    void operator delete(void*) = delete;
+#endif
+    void operator delete[](void*) = delete;
     FrameConstructionItem(const FrameConstructionItem& aOther) = delete; /* not implemented */
+    // Not allocated from the stack!
+    ~FrameConstructionItem()
+    {
+      MOZ_COUNT_DTOR(FrameConstructionItem);
+      MOZ_ASSERT(mChildItems.IsEmpty(), "leaking");
+    }
+  };
+
+  /**
+   * Convenience struct to assist in managing a temporary FrameConstructionItem
+   * using a local variable. Castable to FrameConstructionItem so that it can
+   * be passed transparently to functions that expect that type.
+   * (This struct exists because FrameConstructionItem is arena-allocated, and
+   * it's nice to abstract away its allocation/deallocation.)
+   */
+  struct MOZ_RAII AutoFrameConstructionItem final
+  {
+    template<typename... Args>
+    explicit AutoFrameConstructionItem(nsCSSFrameConstructor* aFCtor, Args&&... args)
+      : mFCtor(aFCtor)
+      , mItem(new (aFCtor) FrameConstructionItem(std::forward<Args>(args)...))
+    { MOZ_ASSERT(mFCtor); }
+    ~AutoFrameConstructionItem() { mItem->Delete(mFCtor); }
+    operator FrameConstructionItem&() { return *mItem; }
+  private:
+    nsCSSFrameConstructor* const mFCtor;
+    FrameConstructionItem* const mItem;
   };
 
   /**
    * Function to create the anonymous flex or grid items that we need.
    * If aParentFrame is not a nsFlexContainerFrame or nsGridContainerFrame then
    * this method is a NOP.
    * @param aItems the child frame construction items before pseudo creation
    * @param aParentFrame the parent frame