Bug 525229 - Crash [@ nsHtml5PendingNotification::nsHtml5PendingNotification] when document.writing an external script followed by start tag. r=bnewman, a=beltzner.
authorHenri Sivonen <hsivonen@iki.fi>
Fri, 30 Oct 2009 13:47:17 +0200
changeset 35295 2f11a4721c944fd6411d9c40c23a5b652db6bb1f
parent 35294 60fea11d79cd3870f3beae1341fc2764074fe195
child 35296 b7f3c1c9fb57ea1b7b4a109b48e1c6b032bb98f8
push idunknown
push userunknown
push dateunknown
reviewersbnewman, beltzner
bugs525229
milestone1.9.3a1pre
Bug 525229 - Crash [@ nsHtml5PendingNotification::nsHtml5PendingNotification] when document.writing an external script followed by start tag. r=bnewman, a=beltzner.
parser/html/nsHtml5Parser.cpp
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeBuilderHSupplement.h
parser/html/nsHtml5TreeOperation.h
--- a/parser/html/nsHtml5Parser.cpp
+++ b/parser/html/nsHtml5Parser.cpp
@@ -597,16 +597,18 @@ nsHtml5Parser::ParseUntilBlocked()
           // never release the last buffer.
           NS_ASSERTION(!mLastBuffer->getStart(), 
             "Sentinel buffer had its indeces changed.");
           NS_ASSERTION(!mLastBuffer->getEnd(), 
             "Sentinel buffer had its indeces changed.");
           if (mStreamParser && 
               mReturnToStreamParserPermitted && 
               !mExecutor->IsScriptExecuting()) {
+            mTreeBuilder->flushCharacters();
+            mTreeBuilder->Flush();
             mReturnToStreamParserPermitted = PR_FALSE;
             mStreamParser->ContinueAfterScripts(mTokenizer, 
                                                 mTreeBuilder, 
                                                 mLastWasCR);
           }
           return; // no more data for now but expecting more
         }
       } else {
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -861,17 +861,20 @@ nsHtml5StreamParser::ContinueAfterScript
       nsHtml5UTF16Buffer* buffer = mFirstBuffer->next;
       while (buffer) {
         buffer->setStart(0);
         buffer = buffer->next;
       }
       
       mSpeculations.Clear(); // potentially a huge number of destructors 
                              // run here synchronously on the main thread...
-      
+
+      mTreeBuilder->flushCharacters(); // empty the pending buffer
+      mTreeBuilder->ClearOps(); // now get rid of the failed ops
+
       mTreeBuilder->SetOpSink(mExecutor->GetStage());
       mExecutor->StartReadingFromStage();
       mSpeculating = PR_FALSE;
       // Copy state over
       mLastWasCR = aLastWasCR;
       mTokenizer->loadState(aTokenizer);
       mTreeBuilder->loadState(aTreeBuilder, &mAtomTable);
     } else {    
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -135,35 +135,40 @@ public:
     return NS_OK;
   }
 };
 
 nsIContent**
 nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes)
 {
   NS_PRECONDITION(aAttributes, "Got null attributes.");
+  NS_PRECONDITION(aName, "Got null name.");
+  NS_PRECONDITION(aNamespace == kNameSpaceID_XHTML || 
+                  aNamespace == kNameSpaceID_SVG || 
+                  aNamespace == kNameSpaceID_MathML,
+                  "Bogus namespace.");
 
   nsIContent** content = AllocateContentHandle();
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(aNamespace, aName, aAttributes, content);
   
   // Start wall of code for speculative loading and line numbers
   
   if (mSpeculativeLoader) {
     switch (aNamespace) {
       case kNameSpaceID_XHTML:
         if (nsHtml5Atoms::img == aName) {
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
           if (url) {
             Dispatch(new nsHtml5SpeculativeImage(mSpeculativeLoader, *url));
           }
         } else if (nsHtml5Atoms::script == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          // XXX if null, OOM!
+          NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
 
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
           if (url) {
             nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
             nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
             Dispatch(new nsHtml5SpeculativeScript(mSpeculativeLoader, 
                                                   *url,
@@ -185,216 +190,244 @@ nsHtml5TreeBuilder::createElement(PRInt3
           }
         } else if (nsHtml5Atoms::video == aName) {
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
           if (url) {
             Dispatch(new nsHtml5SpeculativeImage(mSpeculativeLoader, *url));
           }
         } else if (nsHtml5Atoms::style == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          // XXX if null, OOM!
+          NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
         }
         break;
       case kNameSpaceID_SVG:
         if (nsHtml5Atoms::image == aName) {
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             Dispatch(new nsHtml5SpeculativeImage(mSpeculativeLoader, *url));
           }
         } else if (nsHtml5Atoms::script == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          // XXX if null, OOM!
+          NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
 
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
             Dispatch(new nsHtml5SpeculativeScript(mSpeculativeLoader, 
                                                   *url,
                                                   EmptyString(),
                                                   (type) ? *type : EmptyString()));
           }
         } else if (nsHtml5Atoms::style == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-          // XXX if null, OOM!
+          NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
 
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             Dispatch(new nsHtml5SpeculativeStyle(mSpeculativeLoader, 
                                                  *url,
                                                  EmptyString()));
           }
         }        
         break;
     }
   } else if (aNamespace != kNameSpaceID_MathML) {
     // No speculative loader--just line numbers
     if (nsHtml5Atoms::style == aName) {
       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      // XXX if null, OOM!
+      NS_ASSERTION(treeOp, "Tree op allocation failed.");
       treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
     } else if (nsHtml5Atoms::script == aName) {
       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      // XXX if null, OOM!
+      NS_ASSERTION(treeOp, "Tree op allocation failed.");
       treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
     }
   }
 
   // End wall of code for speculative loading
   
   return content;
 }
 
 nsIContent**
 nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes, nsIContent** aFormElement)
 {
   nsIContent** content = createElement(aNamespace, aName, aAttributes);
   if (aFormElement) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
   }
   return content;
 }
 
 nsIContent**
 nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes)
 {
   nsIContent** content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes);
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppendToDocument, content);
   return content;
 }
 
 void
 nsHtml5TreeBuilder::detachFromParent(nsIContent** aElement)
 {
+  NS_PRECONDITION(aElement, "Null element");
+
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpDetach, aElement);
 }
 
 void
 nsHtml5TreeBuilder::appendElement(nsIContent** aChild, nsIContent** aParent)
 {
+  NS_PRECONDITION(aChild, "Null child");
+  NS_PRECONDITION(aParent, "Null parent");
+
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppend, aChild, aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContent** aOldParent, nsIContent** aNewParent)
 {
+  NS_PRECONDITION(aOldParent, "Null old parent");
+  NS_PRECONDITION(aNewParent, "Null new parent");
+
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent);
 }
 
 void
 nsHtml5TreeBuilder::insertFosterParentedCharacters(PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength, nsIContent** aTable, nsIContent** aStackParent)
 {
+  NS_PRECONDITION(aBuffer, "Null buffer");
+  NS_PRECONDITION(aTable, "Null table");
+  NS_PRECONDITION(aStackParent, "Null stack parent");
+
   PRUnichar* bufferCopy = new PRUnichar[aLength];
   memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
   
   nsIContent** text = AllocateContentHandle();
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpCreateTextNode, bufferCopy, aLength, text);
 
   treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpFosterParent, text, aStackParent, aTable);
 }
 
 void
 nsHtml5TreeBuilder::insertFosterParentedChild(nsIContent** aChild, nsIContent** aTable, nsIContent** aStackParent)
 {
+  NS_PRECONDITION(aChild, "Null child");
+  NS_PRECONDITION(aTable, "Null table");
+  NS_PRECONDITION(aStackParent, "Null stack parent");
+
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable);
 }
 
 void
 nsHtml5TreeBuilder::appendCharacters(nsIContent** aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
 {
+  NS_PRECONDITION(aBuffer, "Null buffer");
+  NS_PRECONDITION(aParent, "Null parent");
+
   PRUnichar* bufferCopy = new PRUnichar[aLength];
   memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
   
   nsIContent** text = AllocateContentHandle();
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpCreateTextNode, bufferCopy, aLength, text);
 
   treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppend, text, aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendComment(nsIContent** aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
 {
+  NS_PRECONDITION(aBuffer, "Null buffer");
+  NS_PRECONDITION(aParent, "Null parent");
+
   PRUnichar* bufferCopy = new PRUnichar[aLength];
   memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
   
   nsIContent** comment = AllocateContentHandle();
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpCreateComment, bufferCopy, aLength, comment);
 
   treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppend, comment, aParent);
 }
 
 void
 nsHtml5TreeBuilder::appendCommentToDocument(PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
 {
+  NS_PRECONDITION(aBuffer, "Null buffer");
+
   PRUnichar* bufferCopy = new PRUnichar[aLength];
   memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
   
   nsIContent** comment = AllocateContentHandle();
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpCreateComment, bufferCopy, aLength, comment);
 
   treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppendToDocument, comment);
 }
 
 void
 nsHtml5TreeBuilder::addAttributesToElement(nsIContent** aElement, nsHtml5HtmlAttributes* aAttributes)
 {
+  NS_PRECONDITION(aElement, "Null element");
+  NS_PRECONDITION(aAttributes, "Null attributes");
+
   if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
     return;
   }
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(aElement, aAttributes);
 }
 
 void
-nsHtml5TreeBuilder::markMalformedIfScript(nsIContent** elt)
+nsHtml5TreeBuilder::markMalformedIfScript(nsIContent** aElement)
 {
+  NS_PRECONDITION(aElement, "Null element");
+
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
-  treeOp->Init(eTreeOpMarkMalformedIfScript, elt);
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
 }
 
 void
 nsHtml5TreeBuilder::start(PRBool fragment)
 {
-  // XXX check that timer creation didn't fail in constructor
 #ifdef DEBUG
   mActive = PR_TRUE;
 #endif
 }
 
 void
 nsHtml5TreeBuilder::end()
 {
@@ -402,40 +435,42 @@ nsHtml5TreeBuilder::end()
 #ifdef DEBUG
   mActive = PR_FALSE;
 #endif
 }
 
 void
 nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId)
 {
+  NS_PRECONDITION(aName, "Null name");
+
   nsIContent** content = AllocateContentHandle();
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(aName, *aPublicId, *aSystemId, content);
   
   treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpAppendToDocument, content);
   // nsXMLContentSink can flush here, but what's the point?
   // It can also interrupt here, but we can't.
 }
 
 void
 nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace, nsIAtom* aName, nsIContent** aElement)
 {
   NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
   NS_ASSERTION(aName, "Element doesn't have local name!");
   NS_ASSERTION(aElement, "No element!");
   // Give autoloading links a chance to fire
   if (aNamespace == kNameSpaceID_XHTML) {
     if (aName == nsHtml5Atoms::html) {
       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-      // XXX if null, OOM!
+      NS_ASSERTION(treeOp, "Tree op allocation failed.");
       treeOp->Init(eTreeOpProcessOfflineManifest, aElement);
       return;
     }
   }
 }
 
 void
 nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent** aElement)
@@ -445,29 +480,29 @@ nsHtml5TreeBuilder::elementPopped(PRInt3
   NS_ASSERTION(aElement, "No element!");
   if (aNamespace == kNameSpaceID_MathML) {
     return;
   }
   // we now have only SVG and HTML
   if (aName == nsHtml5Atoms::script) {
     requestSuspension();
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->InitScript(aElement);
     return;
   }
   if (aName == nsHtml5Atoms::title) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpDoneAddingChildren, aElement);
     return;
   }
   if (aName == nsHtml5Atoms::style || (aNamespace == kNameSpaceID_XHTML && aName == nsHtml5Atoms::link)) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
     return;
   }
   if (aNamespace == kNameSpaceID_SVG) {
 #if 0
     if (aElement->HasAttr(kNameSpaceID_None, nsHtml5Atoms::onload)) {
       nsEvent event(PR_TRUE, NS_SVG_LOAD);
       event.eventStructType = NS_SVG_EVENT;
@@ -495,43 +530,43 @@ nsHtml5TreeBuilder::elementPopped(PRInt3
         aName == nsHtml5Atoms::textarea ||
 #ifdef MOZ_MEDIA
         aName == nsHtml5Atoms::video ||
         aName == nsHtml5Atoms::audio ||
 #endif
         aName == nsHtml5Atoms::object ||
         aName == nsHtml5Atoms::applet) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpDoneAddingChildren, aElement);
     return;
   }
   if (aName == nsHtml5Atoms::input ||
       aName == nsHtml5Atoms::button) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpDoneCreatingElement, aElement);
     return;
   }
   if (aName == nsHtml5Atoms::base) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpProcessBase, aElement);
     return;
   }
   if (aName == nsHtml5Atoms::meta) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpProcessMeta, aElement);
     return;
   }
   if (aName == nsHtml5Atoms::head) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
-    treeOp->Init(eTreeOpStartLayout, nsnull);
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
+    treeOp->Init(eTreeOpStartLayout);
     return;
   }
   return;
 }
 
 void
 nsHtml5TreeBuilder::accumulateCharacters(PRUnichar* aBuf, PRInt32 aStart, PRInt32 aLength)
 {
@@ -550,16 +585,19 @@ nsHtml5TreeBuilder::accumulateCharacters
 nsIContent**
 nsHtml5TreeBuilder::AllocateContentHandle()
 {
   if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) {
     mOldHandles.AppendElement(mHandles.forget());
     mHandles = new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH];
     mHandlesUsed = 0;
   }
+#ifdef DEBUG
+  mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD;
+#endif
   return &mHandles[mHandlesUsed++];
 }
 
 PRBool
 nsHtml5TreeBuilder::HasScript()
 {
   PRUint32 len = mOpQueue.Length();
   if (!len) {
@@ -579,40 +617,40 @@ nsHtml5TreeBuilder::MaybeFlush()
 {
   mOpSink->MaybeFlush(mOpQueue);
 }
 
 void
 nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset)
 {
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpSetDocumentCharset, aCharset);  
 }
 
 void
 nsHtml5TreeBuilder::StreamEnded()
 {
   // The fragment mode calls DidBuildModel from nsHtml5Parser. 
   // Letting DidBuildModel be called from the executor in the fragment case
   // confuses the EndLoad logic of nsHTMLDocument, since nsHTMLDocument
   // thinks it is dealing with document.written content as opposed to 
   // innerHTML content.
   if (!fragment) {
     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-    // XXX if null, OOM!
+    NS_ASSERTION(treeOp, "Tree op allocation failed.");
     treeOp->Init(eTreeOpStreamEnded);
   }
 }
 
 void
 nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString& aCharset)
 {
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(eTreeOpNeedsCharsetSwitchTo, aCharset);  
 }
 
 void
 nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, PRInt32 aLine)
 {
   NS_PRECONDITION(HasScript(), "No script to add a snapshot to!");
   NS_PRECONDITION(aSnapshot, "Got null snapshot.");
@@ -630,11 +668,11 @@ nsHtml5TreeBuilder::DropSpeculativeLoade
   mSpeculativeLoader = nsnull;
 }
 
 // DocumentModeHandler
 void
 nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m)
 {
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
-  // XXX if null, OOM!
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(m);
 }
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -63,16 +63,20 @@
 
     ~nsHtml5TreeBuilder();
     
     PRBool HasScript();
     
     void SetOpSink(nsAHtml5TreeOpSink* aOpSink) {
       mOpSink = aOpSink;
     }
+
+    void ClearOps() {
+      mOpQueue.Clear();
+    }
     
     void SetSpeculativeLoaderWithDocument(nsIDocument* aDocument);
 
     void DropSpeculativeLoader();
 
     void Flush();
     
     void MaybeFlush();
--- a/parser/html/nsHtml5TreeOperation.h
+++ b/parser/html/nsHtml5TreeOperation.h
@@ -112,63 +112,72 @@ class nsHtml5TreeOperation {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
       mOpCode = aOpCode;
     }
 
     inline void Init(eHtml5TreeOperation aOpCode, nsIContent** aNode) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(aNode, "Initialized tree op with null node.");
       mOpCode = aOpCode;
       mOne.node = aNode;
     }
 
     inline void Init(eHtml5TreeOperation aOpCode, 
                      nsIContent** aNode,
                      nsIContent** aParent) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(aNode, "Initialized tree op with null node.");
+      NS_PRECONDITION(aParent, "Initialized tree op with null parent.");
       mOpCode = aOpCode;
       mOne.node = aNode;
       mTwo.node = aParent;
     }
 
     inline void Init(eHtml5TreeOperation aOpCode,
                      nsIContent** aNode,
                      nsIContent** aParent, 
                      nsIContent** aTable) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(aNode, "Initialized tree op with null node.");
+      NS_PRECONDITION(aParent, "Initialized tree op with null parent.");
+      NS_PRECONDITION(aTable, "Initialized tree op with null table.");
       mOpCode = aOpCode;
       mOne.node = aNode;
       mTwo.node = aParent;
       mThree.node = aTable;
     }
 
     inline void Init(nsHtml5DocumentMode aMode) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
       mOpCode = eTreeOpDocumentMode;
       mOne.mode = aMode;
     }
     
     inline void InitScript(nsIContent** aNode) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(aNode, "Initialized tree op with null node.");
       mOpCode = eTreeOpRunScript;
       mOne.node = aNode;
       mTwo.state = nsnull;
     }
     
     inline void Init(PRInt32 aNamespace, 
                      nsIAtom* aName, 
                      nsHtml5HtmlAttributes* aAttributes,
                      nsIContent** aTarget) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(aName, "Initialized tree op with null name.");
+      NS_PRECONDITION(aTarget, "Initialized tree op with null target node.");
       mOpCode = eTreeOpCreateElement;
       mInt = aNamespace;
       mOne.node = aTarget;
       mTwo.atom = aName;
       if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
         mThree.attributes = nsnull;
       } else {
         mThree.attributes = aAttributes;
@@ -176,26 +185,28 @@ class nsHtml5TreeOperation {
     }
 
     inline void Init(eHtml5TreeOperation aOpCode, 
                      PRUnichar* aBuffer, 
                      PRInt32 aLength, 
                      nsIContent** aTarget) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer.");
       mOpCode = aOpCode;
       mOne.node = aTarget;
       mTwo.unicharPtr = aBuffer;
       mInt = aLength;
     }
     
     inline void Init(nsIContent** aElement,
                      nsHtml5HtmlAttributes* aAttributes) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(aElement, "Initialized tree op with null element.");
       mOpCode = eTreeOpAddAttributes;
       mOne.node = aElement;
       mTwo.attributes = aAttributes;
     }
     
     inline void Init(nsIAtom* aName, 
                      const nsAString& aPublicId, 
                      const nsAString& aSystemId, nsIContent** aTarget) {
@@ -223,29 +234,30 @@ class nsHtml5TreeOperation {
       mOne.charPtr = str;
     }
 
     inline void Init(eHtml5TreeOperation aOpCode,
                      nsIContent** aNode,
                      PRInt32 aInt) {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
-
+      NS_PRECONDITION(aNode, "Initialized tree op with null node.");
       mOpCode = aOpCode;
       mOne.node = aNode;
       mInt = aInt;
     }
 
     inline PRBool IsRunScript() {
       return mOpCode == eTreeOpRunScript;
     }
     
     inline void SetSnapshot(nsAHtml5TreeBuilderState* aSnapshot, PRInt32 aLine) {
       NS_ASSERTION(IsRunScript(), 
         "Setting a snapshot for a tree operation other than eTreeOpRunScript!");
+      NS_PRECONDITION(aSnapshot, "Initialized tree op with null snapshot.");
       mTwo.state = aSnapshot;
       mInt = aLine;
     }
 
     nsresult Perform(nsHtml5TreeOpExecutor* aBuilder);
 
     inline already_AddRefed<nsIAtom> Reget(nsIAtom* aAtom) {
       if (!aAtom || aAtom->IsStaticAtom()) {