Back out changeset fc4ddddf142d and changeset d1766aec3d7e due to jsreftest orange.
authorHenri Sivonen <hsivonen@iki.fi>
Sun, 30 Oct 2011 00:10:33 +0300
changeset 79404 f5a12d693b5b4a0170c2dcd8f97fd66d23d7a9e4
parent 79403 fc4ddddf142d3fdb73241ebc14636fca5aa6e76c
child 79405 0ec53cbc126a9b99d6d5751b6c011e02563891a7
push id2994
push userhsivonen@iki.fi
push dateSat, 29 Oct 2011 21:12:13 +0000
treeherdermozilla-inbound@f5a12d693b5b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone10.0a1
backs outfc4ddddf142d3fdb73241ebc14636fca5aa6e76c
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
Back out changeset fc4ddddf142d and changeset d1766aec3d7e due to jsreftest orange.
parser/html/nsHtml5OwningUTF16Buffer.cpp
parser/html/nsHtml5OwningUTF16Buffer.h
parser/html/nsHtml5Parser.cpp
parser/html/nsHtml5UTF16BufferCppSupplement.h
parser/html/nsHtml5UTF16BufferHSupplement.h
parser/htmlparser/tests/reftest/bug696651-1-ref.html
parser/htmlparser/tests/reftest/bug696651-1.html
parser/htmlparser/tests/reftest/bug696651-1.html~
parser/htmlparser/tests/reftest/bug696651-2-ref.html
parser/htmlparser/tests/reftest/bug696651-2.html
parser/htmlparser/tests/reftest/bug696651-2.html~
parser/htmlparser/tests/reftest/bug696651-external.js
parser/htmlparser/tests/reftest/reftest.list
--- a/parser/html/nsHtml5OwningUTF16Buffer.cpp
+++ b/parser/html/nsHtml5OwningUTF16Buffer.cpp
@@ -72,23 +72,16 @@ nsHtml5OwningUTF16Buffer::FalliblyCreate
     new (fallible) nsHtml5OwningUTF16Buffer(newBuf);
   if (!newObj) {
     delete[] newBuf;
     return nsnull;
   }
   return newObj.forget();
 }
 
-void
-nsHtml5OwningUTF16Buffer::Swap(nsHtml5OwningUTF16Buffer* aOther)
-{
-  nsHtml5UTF16Buffer::Swap(aOther);
-}
-
-
 // Not using macros for AddRef and Release in order to be able to refcount on
 // and create on different threads.
 
 nsrefcnt
 nsHtml5OwningUTF16Buffer::AddRef()
 {
   NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "Illegal refcount.");
   ++mRefCnt;
--- a/parser/html/nsHtml5OwningUTF16Buffer.h
+++ b/parser/html/nsHtml5OwningUTF16Buffer.h
@@ -70,20 +70,15 @@ class nsHtml5OwningUTF16Buffer : public 
     /**
      * A parser key.
      */
     void* key;
 
     static already_AddRefed<nsHtml5OwningUTF16Buffer>
     FalliblyCreate(PRInt32 aLength);
 
-    /**
-     * Swap start, end and buffer fields with another object.
-     */
-    void Swap(nsHtml5OwningUTF16Buffer* aOther);
-
     nsrefcnt AddRef();
     nsrefcnt Release();
   private:
     nsAutoRefCnt mRefCnt;
 };
 
 #endif // nsHtml5OwningUTF16Buffer_h_
--- a/parser/html/nsHtml5Parser.cpp
+++ b/parser/html/nsHtml5Parser.cpp
@@ -282,113 +282,35 @@ nsHtml5Parser::Parse(const nsAString& aS
     return NS_OK;
   }
 
   if (aLastCall && aSourceBuffer.IsEmpty() && aKey == GetRootContextKey()) {
     // document.close()
     NS_ASSERTION(!mStreamParser,
                  "Had stream parser but got document.close().");
     mDocumentClosed = true;
-    if (!mBlocked && !mInDocumentWrite) {
+    if (!mBlocked) {
       ParseUntilBlocked();
     }
     return NS_OK;
   }
 
-  // If we got this far, we are dealing with a document.write or
-  // document.writeln call--not document.close().
-
   NS_ASSERTION(IsInsertionPointDefined(),
                "Doc.write reached parser with undefined insertion point.");
 
   NS_ASSERTION(!(mStreamParser && !aKey),
                "Got a null key in a non-script-created parser");
 
-  // XXX is this optimization bogus?
   if (aSourceBuffer.IsEmpty()) {
     return NS_OK;
   }
 
-  // This guard is here to prevent document.close from tokenizing synchronously
-  // while a document.write (that wrote the script that called document.close!)
-  // is still on the call stack.
   mozilla::AutoRestore<bool> guard(mInDocumentWrite);
   mInDocumentWrite = true;
 
-  // The script is identified by aKey. If there's nothing in the buffer
-  // chain for that key, we'll insert at the head of the queue.
-  // When the script leaves something in the queue, a zero-length
-  // key-holder "buffer" is inserted in the queue. If the same script
-  // leaves something in the chain again, it will be inserted immediately
-  // before the old key holder belonging to the same script.
-  //
-  // We don't do the actual data insertion yet in the hope that the data gets
-  // tokenized and there no data or less data to copy to the heap after
-  // tokenization. Also, this way, we avoid inserting one empty data buffer
-  // per document.write, which matters for performance when the parser isn't
-  // blocked and a badly-authored script calls document.write() once per
-  // input character. (As seen in a benchmark!)
-  //
-  // The insertion into the input stream happens conceptually before anything
-  // gets tokenized. To make sure multi-level document.write works right,
-  // it's necessary to establish the location of our parser key up front
-  // in case this is the first write with this key.
-  //
-  // In a document.open() case, the first write level has a null key, so that
-  // case is handled separately, because normal buffers containing data
-  // have null keys.
-
-  nsHtml5OwningUTF16Buffer* prevSearchBuf = nsnull;
-  nsHtml5OwningUTF16Buffer* firstLevelMarker = nsnull;
-
-  if (aKey) {
-    if (mFirstBuffer == mLastBuffer) {
-      nsHtml5OwningUTF16Buffer* keyHolder = new nsHtml5OwningUTF16Buffer(aKey);
-      keyHolder->next = mLastBuffer;
-      mFirstBuffer = keyHolder;
-    } else {
-      prevSearchBuf = mFirstBuffer;
-      for (;;) {
-        if (prevSearchBuf->next == mLastBuffer) {
-          // key was not found
-          nsHtml5OwningUTF16Buffer* keyHolder =
-            new nsHtml5OwningUTF16Buffer(aKey);
-          keyHolder->next = mFirstBuffer;
-          mFirstBuffer = keyHolder;
-          prevSearchBuf = nsnull;
-          break;
-        }
-        if (prevSearchBuf->next->key == aKey) {
-          // found a key holder
-          break;
-        }
-        prevSearchBuf = prevSearchBuf->next;
-      }
-    }
-    // prevSearchBuf is the previous buffer before the keyholder or null if
-    // there isn't one.
-  } else {
-    // We have a first-level write in the document.open() case. We insert
-    // before mLastBuffer. We need to put a marker there, because otherwise
-    // additional document.writes from nested event loops would insert in the
-    // wrong place. Sigh.
-    firstLevelMarker = new nsHtml5OwningUTF16Buffer((void*)nsnull);
-    if (mFirstBuffer == mLastBuffer) {
-      firstLevelMarker->next = mLastBuffer;
-      mFirstBuffer = firstLevelMarker;
-    } else {
-      prevSearchBuf = mFirstBuffer;
-      while (prevSearchBuf->next != mLastBuffer) {
-        prevSearchBuf = prevSearchBuf->next;
-      }
-      firstLevelMarker->next = mLastBuffer;
-      prevSearchBuf->next = firstLevelMarker;
-    }
-  }
-
   nsHtml5DependentUTF16Buffer stackBuffer(aSourceBuffer);
 
   while (!mBlocked && stackBuffer.hasMore()) {
     stackBuffer.adjust(mLastWasCR);
     mLastWasCR = false;
     if (stackBuffer.hasMore()) {
       PRInt32 lineNumberSave;
       bool inRootContext = (!mStreamParser && (aKey == mRootContextKey));
@@ -428,45 +350,70 @@ nsHtml5Parser::Parse(const nsAString& aS
     heapBuffer = stackBuffer.FalliblyCopyAsOwningBuffer();
     if (!heapBuffer) {
       // Allocation failed. The parser is now broken.
       mExecutor->MarkAsBroken();
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
-  if (heapBuffer) {
-    // We have something to insert before the keyholder holding in the non-null
-    // aKey case and we have something to swap into firstLevelMarker in the
-    // null aKey case.
-    if (aKey) {
-      NS_ASSERTION(mFirstBuffer != mLastBuffer,
-        "Where's the keyholder?");
-      // the key holder is still somewhere further down the list from
-      // prevSearchBuf (which may be null)
-      if (mFirstBuffer->key == aKey) {
-        NS_ASSERTION(!prevSearchBuf,
-          "Non-null prevSearchBuf when mFirstBuffer is the key holder?");
-        heapBuffer->next = mFirstBuffer;
+  // The buffer is inserted to the stream here in case it won't be parsed
+  // to completion.
+  // The script is identified by aKey. If there's nothing in the buffer
+  // chain for that key, we'll insert at the head of the queue.
+  // When the script leaves something in the queue, a zero-length
+  // key-holder "buffer" is inserted in the queue. If the same script
+  // leaves something in the chain again, it will be inserted immediately
+  // before the old key holder belonging to the same script.
+  nsHtml5OwningUTF16Buffer* prevSearchBuf = nsnull;
+  nsHtml5OwningUTF16Buffer* searchBuf = mFirstBuffer;
+
+  // after document.open, the first level of document.write has null key
+  if (aKey) {
+    while (searchBuf != mLastBuffer) {
+      if (searchBuf->key == aKey) {
+        // found a key holder
+        // now insert the new buffer between the previous buffer
+        // and the key holder if we have a buffer left.
+        if (heapBuffer) {
+          heapBuffer->next = searchBuf;
+          if (prevSearchBuf) {
+            prevSearchBuf->next = heapBuffer;
+          } else {
+            mFirstBuffer = heapBuffer;
+          }
+        }
+        break;
+      }
+      prevSearchBuf = searchBuf;
+      searchBuf = searchBuf->next;
+    }
+    if (searchBuf == mLastBuffer) {
+      // key was not found
+      nsHtml5OwningUTF16Buffer* keyHolder = new nsHtml5OwningUTF16Buffer(aKey);
+      keyHolder->next = mFirstBuffer;
+      if (heapBuffer) {
+        heapBuffer->next = keyHolder;
         mFirstBuffer = heapBuffer;
       } else {
-        if (!prevSearchBuf) {
-          prevSearchBuf = mFirstBuffer;
-        }
-        // We created a key holder earlier, so we will find it without walking
-        // past the end of the list.
-        while (prevSearchBuf->next->key != aKey) {
-          prevSearchBuf = prevSearchBuf->next;
-        }
-        heapBuffer->next = prevSearchBuf->next;
-        prevSearchBuf->next = heapBuffer;
+        mFirstBuffer = keyHolder;
       }
+    }
+  } else if (heapBuffer) {
+    // we have a first level document.write after document.open()
+    // insert immediately before mLastBuffer
+    while (searchBuf != mLastBuffer) {
+      prevSearchBuf = searchBuf;
+      searchBuf = searchBuf->next;
+    }
+    heapBuffer->next = mLastBuffer;
+    if (prevSearchBuf) {
+      prevSearchBuf->next = heapBuffer;
     } else {
-      NS_ASSERTION(firstLevelMarker, "How come we don't have a marker.");
-      firstLevelMarker->Swap(heapBuffer);
+      mFirstBuffer = heapBuffer;
     }
   }
 
   if (!mBlocked) { // buffer was tokenized to completion
     NS_ASSERTION(!stackBuffer.hasMore(),
       "Buffer wasn't tokenized to completion?");
     // Scripting semantics require a forced tree builder flush here
     mTreeBuilder->Flush(); // Move ops to the executor
@@ -705,22 +652,24 @@ nsHtml5Parser::IsScriptCreated()
 
 // not from interface
 void
 nsHtml5Parser::ParseUntilBlocked()
 {
   NS_PRECONDITION(!mExecutor->IsFragmentMode(),
                   "ParseUntilBlocked called in fragment mode.");
 
-  if (mBlocked || mExecutor->IsComplete() || mExecutor->IsBroken()) {
+  if (mBlocked ||
+      mExecutor->IsComplete() ||
+      mExecutor->IsBroken() ||
+      mInDocumentWrite) {
     return;
   }
+
   NS_ASSERTION(mExecutor->HasStarted(), "Bad life cycle.");
-  NS_ASSERTION(!mInDocumentWrite,
-    "ParseUntilBlocked entered while in doc.write!");
 
   mDocWriteSpeculatorActive = false;
 
   for (;;) {
     if (!mFirstBuffer->hasMore()) {
       if (mFirstBuffer == mLastBuffer) {
         if (mExecutor->IsComplete()) {
           // something like cache manisfests stopped the parse in mid-flight
--- a/parser/html/nsHtml5UTF16BufferCppSupplement.h
+++ b/parser/html/nsHtml5UTF16BufferCppSupplement.h
@@ -48,22 +48,8 @@ nsHtml5UTF16Buffer::~nsHtml5UTF16Buffer(
   MOZ_COUNT_DTOR(nsHtml5UTF16Buffer);
 }
 
 void
 nsHtml5UTF16Buffer::DeleteBuffer()
 {
   delete[] buffer;
 }
-
-void
-nsHtml5UTF16Buffer::Swap(nsHtml5UTF16Buffer* aOther)
-{
-  PRUnichar* tempBuffer = buffer;
-  PRInt32 tempStart = start;
-  PRInt32 tempEnd = end;
-  buffer = aOther->buffer;
-  start = aOther->start;
-  end = aOther->end;
-  aOther->buffer = tempBuffer;
-  aOther->start = tempStart;
-  aOther->end = tempEnd;
-}
--- a/parser/html/nsHtml5UTF16BufferHSupplement.h
+++ b/parser/html/nsHtml5UTF16BufferHSupplement.h
@@ -38,13 +38,8 @@
 protected:
   nsHtml5UTF16Buffer(PRUnichar* aBuffer, PRInt32 aEnd);
   ~nsHtml5UTF16Buffer();
 
   /**
    * For working around the privacy of |buffer| in the generated code.
    */
   void DeleteBuffer();
-
-  /**
-   * For working around the privacy of |buffer| in the generated code.
-   */
-  void Swap(nsHtml5UTF16Buffer* aOther);
deleted file mode 100644
--- a/parser/htmlparser/tests/reftest/bug696651-1-ref.html
+++ /dev/null
@@ -1,1 +0,0 @@
-<!DOCTYPE html>CcBbAa
deleted file mode 100644
--- a/parser/htmlparser/tests/reftest/bug696651-1.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<body><script>document.write("\u003cscript>document.write(\"\\u003cscript  src='bug696651-external.js'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); document.write("a");</script>
deleted file mode 100644
--- a/parser/htmlparser/tests/reftest/bug696651-1.html~
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<body><script>document.write("\u003cscript>document.write(\"\\u003cscript src='data:text/javascript,document.write(%27C%27);%20document.write(%27c%27);'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); document.write("a");</script>
deleted file mode 100644
--- a/parser/htmlparser/tests/reftest/bug696651-2-ref.html
+++ /dev/null
@@ -1,1 +0,0 @@
-<!DOCTYPE html><iframe src="data:text/html,<!DOCTYPE html>CcBbAa"></iframe>
deleted file mode 100644
--- a/parser/htmlparser/tests/reftest/bug696651-2.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE html>
-<body>
-<iframe></iframe>
-<script>
-var doc = document.getElementsByTagName("iframe")[0].contentDocument;
-doc.open(); doc.write("\u003cscript>document.write(\"\\u003cscript src='bug696651-external.js'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); doc.write("a"); doc.close();</script>
deleted file mode 100644
--- a/parser/htmlparser/tests/reftest/bug696651-2.html~
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE html>
-<body>
-<iframe></iframe>
-<script>
-var doc = document.getElementsByTagName("iframe")[0].contentDocument;
-doc.open(); doc.write("\u003cscript>document.write(\"\\u003cscript src='data:text/javascript,document.write(%27C%27);%20document.write(%27c%27);'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); doc.write("a"); doc.close();</script>
deleted file mode 100644
--- a/parser/htmlparser/tests/reftest/bug696651-external.js
+++ /dev/null
@@ -1,1 +0,0 @@
-document.write("C"); document.write("c");
--- a/parser/htmlparser/tests/reftest/reftest.list
+++ b/parser/htmlparser/tests/reftest/reftest.list
@@ -1,9 +1,7 @@
 == bug566280-1.html bug566280-1-ref.html
 == bug577418-1.html bug577418-1-ref.html
 == bug582788-1.html bug582788-1-ref.html
 == bug582940-1.html bug582940-1-ref.html
 == bug592656-1.html bug592656-1-ref.html
 == bug608373-1.html bug608373-1-ref.html
 == view-source:bug673094-1.html view-source:bug673094-1-ref.html
-== bug696651-1.html bug696651-1-ref.html
-== bug696651-2.html bug696651-2-ref.html