Bug 1413467 - Make enqueueing tree ops use fallible allocation. draft
authorHenri Sivonen <hsivonen@hsivonen.fi>
Fri, 10 Nov 2017 12:19:45 +0200
changeset 696803 0822ce76a1f1d6c07e979c7c19461494c95a95d6
parent 694173 e13804265867ec492d8b775035698b1bcd8b96f8
child 739923 a4e4664cdd2cf17eb92b07dde74a32cd2cf4bbc3
push id88786
push userbmo:hsivonen@hsivonen.fi
push dateSat, 11 Nov 2017 10:41:15 +0000
bugs1413467
milestone58.0a1
Bug 1413467 - Make enqueueing tree ops use fallible allocation. MozReview-Commit-ID: 9GI3btVYLqL
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeBuilderHSupplement.h
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -118,18 +118,21 @@ nsHtml5TreeBuilder::createElement(int32_
     if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
                      aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
       delete aAttributes;
     }
     return elem;
   }
 
   nsIContentHandle* content = AllocateContentHandle();
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
   treeOp->Init(aNamespace,
                aName,
                aAttributes,
                content,
                aIntendedParent,
                !!mSpeculativeLoadStage,
                aCreator);
   // mSpeculativeLoadStage is non-null only in the off-the-main-thread
@@ -165,18 +168,23 @@ nsHtml5TreeBuilder::createElement(int32_
             nsHtml5String type =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
             nsHtml5String media =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
             mSpeculativeLoadQueue.AppendElement()->InitPictureSource(
               srcset, sizes, type, media);
           }
         } else if (nsGkAtoms::script == aName) {
-          nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          NS_ASSERTION(treeOp, "Tree op allocation failed.");
+          nsHtml5TreeOperation* treeOp =
+            mOpQueue.AppendElement(mozilla::fallible);
+          if (MOZ_UNLIKELY(!treeOp)) {
+            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
+              NS_ERROR_OUT_OF_MEMORY);
+            return nullptr;
+          }
           treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
 
           nsHtml5String url =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
           if (url) {
             nsHtml5String charset =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
             nsHtml5String type =
@@ -235,18 +243,23 @@ nsHtml5TreeBuilder::createElement(int32_
         } else if (nsGkAtoms::video == aName) {
           nsHtml5String url =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
           if (url) {
             mSpeculativeLoadQueue.AppendElement()->InitImage(
               url, nullptr, nullptr, nullptr, nullptr);
           }
         } else if (nsGkAtoms::style == aName) {
-          nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          NS_ASSERTION(treeOp, "Tree op allocation failed.");
+          nsHtml5TreeOperation* treeOp =
+            mOpQueue.AppendElement(mozilla::fallible);
+          if (MOZ_UNLIKELY(!treeOp)) {
+            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
+              NS_ERROR_OUT_OF_MEMORY);
+            return nullptr;
+          }
           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
         } else if (nsGkAtoms::html == aName) {
           nsHtml5String url =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
           mSpeculativeLoadQueue.AppendElement()->InitManifest(url);
         } else if (nsGkAtoms::base == aName) {
           nsHtml5String url =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
@@ -279,18 +292,23 @@ nsHtml5TreeBuilder::createElement(int32_
         if (nsGkAtoms::image == aName) {
           nsHtml5String url =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             mSpeculativeLoadQueue.AppendElement()->InitImage(
               url, nullptr, nullptr, nullptr, nullptr);
           }
         } else if (nsGkAtoms::script == aName) {
-          nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          NS_ASSERTION(treeOp, "Tree op allocation failed.");
+          nsHtml5TreeOperation* treeOp =
+            mOpQueue.AppendElement(mozilla::fallible);
+          if (MOZ_UNLIKELY(!treeOp)) {
+            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
+              NS_ERROR_OUT_OF_MEMORY);
+            return nullptr;
+          }
           treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
 
           nsHtml5String url =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             nsHtml5String type =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
             nsHtml5String crossOrigin =
@@ -303,18 +321,23 @@ nsHtml5TreeBuilder::createElement(int32_
               type,
               crossOrigin,
               integrity,
               mode == nsHtml5TreeBuilder::IN_HEAD,
               false,
               false);
           }
         } else if (nsGkAtoms::style == aName) {
-          nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          NS_ASSERTION(treeOp, "Tree op allocation failed.");
+          nsHtml5TreeOperation* treeOp =
+            mOpQueue.AppendElement(mozilla::fallible);
+          if (MOZ_UNLIKELY(!treeOp)) {
+            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
+              NS_ERROR_OUT_OF_MEMORY);
+            return nullptr;
+          }
           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
 
           nsHtml5String url =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             nsHtml5String crossOrigin =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
             nsHtml5String integrity =
@@ -325,35 +348,46 @@ nsHtml5TreeBuilder::createElement(int32_
               url, nullptr, crossOrigin, referrerPolicy, integrity);
           }
         }
         break;
     }
   } else if (aNamespace != kNameSpaceID_MathML) {
     // No speculative loader--just line numbers and defer/async check
     if (nsGkAtoms::style == aName) {
-      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      NS_ASSERTION(treeOp, "Tree op allocation failed.");
+      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+      if (MOZ_UNLIKELY(!treeOp)) {
+        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+        return nullptr;
+      }
       treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
     } else if (nsGkAtoms::script == aName) {
-      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      NS_ASSERTION(treeOp, "Tree op allocation failed.");
+      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+      if (MOZ_UNLIKELY(!treeOp)) {
+        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+        return nullptr;
+      }
       treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
       if (aNamespace == kNameSpaceID_XHTML) {
         mCurrentHtmlScriptIsAsyncOrDefer = 
           aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) &&
           (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
            aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER));
       }
     } else if (aNamespace == kNameSpaceID_XHTML) {
       if (nsGkAtoms::html == aName) {
         nsHtml5String url =
           aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
-        nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-        NS_ASSERTION(treeOp, "Tree op allocation failed.");
+        nsHtml5TreeOperation* treeOp =
+          mOpQueue.AppendElement(mozilla::fallible);
+        if (MOZ_UNLIKELY(!treeOp)) {
+          MarkAsBrokenAndRequestSuspensionWithoutBuilder(
+            NS_ERROR_OUT_OF_MEMORY);
+          return nullptr;
+        }
         if (url) {
           nsString
             urlString; // Not Auto, because using it to hold nsStringBuffer*
           url.ToString(urlString);
           treeOp->Init(eTreeOpProcessOfflineManifest, urlString);
         } else {
           treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString());
         }
@@ -382,18 +416,21 @@ nsHtml5TreeBuilder::createElement(int32_
 {
   nsIContentHandle* content =
     createElement(aNamespace, aName, aAttributes, aIntendedParent, aCreator);
   if (aFormElement) {
     if (mBuilder) {
       nsHtml5TreeOperation::SetFormElement(static_cast<nsIContent*>(content),
         static_cast<nsIContent*>(aFormElement));
     } else {
-      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      NS_ASSERTION(treeOp, "Tree op allocation failed.");
+      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+      if (MOZ_UNLIKELY(!treeOp)) {
+        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+        return nullptr;
+      }
       treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
     }
   }
   return content;
 }
 
 nsIContentHandle*
 nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes)
@@ -402,21 +439,24 @@ nsHtml5TreeBuilder::createHtmlElementSet
   // <html> uses NS_NewHTMLSharedElement creator
   creator.html = NS_NewHTMLSharedElement;
   nsIContentHandle* content = createElement(
     kNameSpaceID_XHTML, nsGkAtoms::html, aAttributes, nullptr, creator);
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::AppendToDocument(static_cast<nsIContent*>(content),
                                                          mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
   } else {
-    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+    if (MOZ_UNLIKELY(!treeOp)) {
+      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+      return nullptr;
+    }
     treeOp->Init(eTreeOpAppendToDocument, content);
   }
   return content;
 }
 
 nsIContentHandle*
 nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
   int32_t aNamespace,
@@ -469,18 +509,21 @@ nsHtml5TreeBuilder::detachFromParent(nsI
   NS_PRECONDITION(aElement, "Null element");
 
   if (mBuilder) {
     nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement),
                                  mBuilder);
     return;
   }
 
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpDetach, aElement);
 }
 
 void
 nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, nsIContentHandle* aParent)
 {
   NS_PRECONDITION(aChild, "Null child");
   NS_PRECONDITION(aParent, "Null parent");
@@ -488,45 +531,51 @@ nsHtml5TreeBuilder::appendElement(nsICon
     return;
   }
 
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::Append(static_cast<nsIContent*>(aChild),
                                                static_cast<nsIContent*>(aParent),
                                                mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpAppend, aChild, aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent, nsIContentHandle* aNewParent)
 {
   NS_PRECONDITION(aOldParent, "Null old parent");
   NS_PRECONDITION(aNewParent, "Null new parent");
 
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
       static_cast<nsIContent*>(aOldParent),
       static_cast<nsIContent*>(aNewParent),
       mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent);
 }
 
 void
 nsHtml5TreeBuilder::insertFosterParentedCharacters(char16_t* aBuffer, int32_t aStart, int32_t aLength, nsIContentHandle* aTable, nsIContentHandle* aStackParent)
 {
   NS_PRECONDITION(aBuffer, "Null buffer");
   NS_PRECONDITION(aTable, "Null table");
@@ -536,34 +585,37 @@ nsHtml5TreeBuilder::insertFosterParented
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::FosterParentText(
       static_cast<nsIContent*>(aStackParent),
       aBuffer, // XXX aStart always ignored???
       aLength,
       static_cast<nsIContent*>(aTable),
       mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
   if (!bufferCopy) {
     // Just assigning mBroken instead of generating tree op. The caller
     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
     mBroken = NS_ERROR_OUT_OF_MEMORY;
     requestSuspension();
     return;
   }
 
   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
-  
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpFosterParentText, bufferCopy, aLength, aStackParent, aTable);
 }
 
 void
 nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild, nsIContentHandle* aTable, nsIContentHandle* aStackParent)
 {
   NS_PRECONDITION(aChild, "Null child");
   NS_PRECONDITION(aTable, "Null table");
@@ -571,23 +623,26 @@ nsHtml5TreeBuilder::insertFosterParented
 
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::FosterParent(
       static_cast<nsIContent*>(aChild),
       static_cast<nsIContent*>(aStackParent),
       static_cast<nsIContent*>(aTable),
       mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable);
 }
 
 void
 nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength)
 {
   NS_PRECONDITION(aBuffer, "Null buffer");
   NS_PRECONDITION(aParent, "Null parent");
@@ -596,34 +651,37 @@ nsHtml5TreeBuilder::appendCharacters(nsI
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::AppendText(
       aBuffer, // XXX aStart always ignored???
       aLength,
       static_cast<nsIContent*>(deepTreeSurrogateParent ?
                                deepTreeSurrogateParent : aParent),
       mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
   if (!bufferCopy) {
     // Just assigning mBroken instead of generating tree op. The caller
     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
     mBroken = NS_ERROR_OUT_OF_MEMORY;
     requestSuspension();
     return;
   }
 
   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
-  
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpAppendText, bufferCopy, aLength,
       deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength)
 {
   NS_PRECONDITION(aBuffer, "Null buffer");
@@ -636,67 +694,73 @@ nsHtml5TreeBuilder::appendComment(nsICon
 
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::AppendComment(
       static_cast<nsIContent*>(aParent),
       aBuffer, // XXX aStart always ignored???
       aLength,
       mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
   if (!bufferCopy) {
     // Just assigning mBroken instead of generating tree op. The caller
     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
     mBroken = NS_ERROR_OUT_OF_MEMORY;
     requestSuspension();
     return;
   }
 
   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
-  
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpAppendComment, bufferCopy, aLength, aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer, int32_t aStart, int32_t aLength)
 {
   NS_PRECONDITION(aBuffer, "Null buffer");
   MOZ_ASSERT(!aStart, "aStart must always be zero.");
 
   if (mBuilder) {
     nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument(
       aBuffer, // XXX aStart always ignored???
       aLength,
       mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
   if (!bufferCopy) {
     // Just assigning mBroken instead of generating tree op. The caller
     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
     mBroken = NS_ERROR_OUT_OF_MEMORY;
     requestSuspension();
     return;
   }
 
   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
-  
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy, aLength);
 }
 
 void
 nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes)
 {
   NS_PRECONDITION(aElement, "Null element");
   NS_PRECONDITION(aAttributes, "Null attributes");
@@ -708,39 +772,45 @@ nsHtml5TreeBuilder::addAttributesToEleme
   if (mBuilder) {
     MOZ_ASSERT(aAttributes == tokenizer->GetAttributes(),
       "Using attribute other than the tokenizer's to add to body or html.");
     nsresult rv = nsHtml5TreeOperation::AddAttributes(
       static_cast<nsIContent*>(aElement),
       aAttributes,
       mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(aElement, aAttributes);
 }
 
 void
 nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement)
 {
   NS_PRECONDITION(aElement, "Null element");
 
   if (mBuilder) {
     nsHtml5TreeOperation::MarkMalformedIfScript(
       static_cast<nsIContent*>(aElement));
     return;
   }
 
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
 }
 
 void
 nsHtml5TreeBuilder::start(bool fragment)
 {
   mCurrentHtmlScriptIsAsyncOrDefer = false;
   deepTreeSurrogateParent = nullptr;
@@ -768,23 +838,26 @@ nsHtml5TreeBuilder::appendDoctypeToDocum
   nsString systemId; // Not Auto, because using it to hold nsStringBuffer*
   aPublicId.ToString(publicId);
   aSystemId.ToString(systemId);
   if (mBuilder) {
     RefPtr<nsAtom> name = nsHtml5TreeOperation::Reget(aName);
     nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument(
       name, publicId, systemId, mBuilder);
     if (NS_FAILED(rv)) {
-      MarkAsBrokenAndRequestSuspension(rv);
+      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
     }
     return;
   }
 
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(aName, publicId, systemId);
   // nsXMLContentSink can flush here, but what's the point?
   // It can also interrupt here, but we can't.
 }
 
 void
 nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsAtom* aName, nsIContentHandle* aElement)
 {
@@ -820,18 +893,21 @@ nsHtml5TreeBuilder::elementPushed(int32_
   if (aNamespace != kNameSpaceID_XHTML) {
     return;
   }
   if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) {
     if (mBuilder) {
       // InnerHTML and DOMParser shouldn't start layout anyway
       return;
     }
-    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+    if (MOZ_UNLIKELY(!treeOp)) {
+      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
     treeOp->Init(eTreeOpStartLayout);
     return;
   }
   if (aName == nsGkAtoms::input || aName == nsGkAtoms::button) {
     if (mBuilder) {
       nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement));
     } else {
       mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
@@ -879,83 +955,104 @@ nsHtml5TreeBuilder::elementPopped(int32_
       return;
     }
     if (mBuilder) {
       return;
     }
     if (mCurrentHtmlScriptIsAsyncOrDefer) {
       NS_ASSERTION(aNamespace == kNameSpaceID_XHTML, 
                    "Only HTML scripts may be async/defer.");
-      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      NS_ASSERTION(treeOp, "Tree op allocation failed.");
+      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+      if (MOZ_UNLIKELY(!treeOp)) {
+        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+        return;
+      }
       treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement);      
       mCurrentHtmlScriptIsAsyncOrDefer = false;
       return;
     }
     requestSuspension();
-    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+    if (MOZ_UNLIKELY(!treeOp)) {
+      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
     treeOp->InitScript(aElement);
     return;
   }
   if (aName == nsGkAtoms::title) {
     if (mBuilder) {
       nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement));
       return;
     }
-    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+    if (MOZ_UNLIKELY(!treeOp)) {
+      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
     treeOp->Init(eTreeOpDoneAddingChildren, aElement);
     return;
   }
   if (aName == nsGkAtoms::style ||
       (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::link)) {
     if (mBuilder) {
       MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
         "Scripts must be blocked.");
       mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement));
       return;
     }
-    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+    if (MOZ_UNLIKELY(!treeOp)) {
+      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
     treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
     return;
   }
   if (aNamespace == kNameSpaceID_SVG) {
     if (aName == nsGkAtoms::svg) {
       if (mBuilder) {
         nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
         return;
       }
-      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      NS_ASSERTION(treeOp, "Tree op allocation failed.");
+      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+      if (MOZ_UNLIKELY(!treeOp)) {
+        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+        return;
+      }
       treeOp->Init(eTreeOpSvgLoad, aElement);
     }
     return;
   }
   // we now have only HTML
   // Some HTML nodes need DoneAddingChildren() called to initialize
   // properly (e.g. form state restoration).
   // XXX expose ElementName group here and do switch
   if (aName == nsGkAtoms::object ||
       aName == nsGkAtoms::select ||
       aName == nsGkAtoms::textarea ||
       aName == nsGkAtoms::output) {
     if (mBuilder) {
       nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement));
       return;
     }
-    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+    if (MOZ_UNLIKELY(!treeOp)) {
+      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
     treeOp->Init(eTreeOpDoneAddingChildren, aElement);
     return;
   }
   if (aName == nsGkAtoms::meta && !fragment && !mBuilder) {
-    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+    if (MOZ_UNLIKELY(!treeOp)) {
+      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
     treeOp->Init(eTreeOpProcessMeta, aElement);
     return;
   }
   if (mSpeculativeLoadStage && aName == nsGkAtoms::picture) {
     // mSpeculativeLoadStage is non-null only in the off-the-main-thread
     // tree builder, which handles the network stream
     //
     // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
@@ -1110,32 +1207,38 @@ nsHtml5TreeBuilder::SetDocumentCharset(N
   }
 }
 
 void
 nsHtml5TreeBuilder::StreamEnded()
 {
   MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder.");
   MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread.");
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpStreamEnded);
 }
 
 void
 nsHtml5TreeBuilder::NeedsCharsetSwitchTo(NotNull<const Encoding*> aEncoding,
                                          int32_t aCharsetSource,
                                          int32_t aLineNumber)
 {
   if (MOZ_UNLIKELY(mBuilder)) {
     MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder.");
     return;
   }
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(eTreeOpNeedsCharsetSwitchTo,
                aEncoding,
                aCharsetSource,
                aLineNumber);
 }
 
 void
 nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId,
@@ -1180,17 +1283,17 @@ nsHtml5TreeBuilder::MarkAsBroken(nsresul
   mOpQueue.Clear(); // Previous ops don't matter anymore
   mOpQueue.AppendElement()->Init(aRv);
 }
 
 void
 nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv)
 {
   if (mBuilder) {
-    MarkAsBrokenAndRequestSuspension(aRv);
+    MarkAsBrokenAndRequestSuspensionWithBuilder(aRv);
     return;
   }
   mBroken = aRv;
   requestSuspension();
 }
 
 void
 nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
@@ -1247,29 +1350,35 @@ nsHtml5TreeBuilder::documentMode(nsHtml5
   if (mBuilder) {
     mBuilder->SetDocumentMode(m);
     return;
   }
   if (mSpeculativeLoadStage) {
     mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m);
     return;
   }
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
   treeOp->Init(m);
 }
 
 nsIContentHandle*
 nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate)
 {
   if (mBuilder) {
     return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(static_cast<nsIContent*>(aTemplate));
   }
-  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
+  if (MOZ_UNLIKELY(!treeOp)) {
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
   nsIContentHandle* fragHandle = AllocateContentHandle();
   treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle);
   return fragHandle;
 }
 
 nsIContentHandle*
 nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext)
 {
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -62,22 +62,30 @@
      */
     nsIContentHandle* AllocateContentHandle();
     
     void accumulateCharactersForced(const char16_t* aBuf, int32_t aStart, int32_t aLength)
     {
       accumulateCharacters(aBuf, aStart, aLength);
     }
 
-    void MarkAsBrokenAndRequestSuspension(nsresult aRv)
+    void
+    MarkAsBrokenAndRequestSuspensionWithBuilder(nsresult aRv)
     {
       mBuilder->MarkAsBroken(aRv);
       requestSuspension();
     }
 
+    void
+    MarkAsBrokenAndRequestSuspensionWithoutBuilder(nsresult aRv)
+    {
+      MarkAsBroken(aRv);
+      requestSuspension();
+    }
+
     void MarkAsBrokenFromPortability(nsresult aRv);
 
   public:
 
     explicit nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder);
 
     nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
                        nsHtml5TreeOpStage* aStage);