Bug 1151048. Disable speculative tokenization in the parser if it's failing too much. r=hsivonen
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 13 Apr 2015 19:36:33 -0400
changeset 270307 d22bb27be448fc5397d014a62ae4087e83fecc72
parent 270306 f65fd10ee5a7bf7082f1edbf5e5ce64d4c06780c
child 270308 5b4b5f04f545a299f43ec6c4ca3802e8c10237ae
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs1151048
milestone40.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 1151048. Disable speculative tokenization in the parser if it's failing too much. r=hsivonen
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5StreamParser.h
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -1310,17 +1310,21 @@ void
 nsHtml5StreamParser::ParseAvailableData()
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   mTokenizerMutex.AssertCurrentThreadOwns();
 
   if (IsTerminatedOrInterrupted()) {
     return;
   }
-  
+
+  if (mSpeculating && !IsSpeculationEnabled()) {
+    return;
+  }
+
   for (;;) {
     if (!mFirstBuffer->hasMore()) {
       if (mFirstBuffer == mLastBuffer) {
         switch (mStreamState) {
           case STREAM_BEING_READ:
             // never release the last buffer.
             if (!mSpeculating) {
               // reuse buffer space if not speculating
@@ -1449,16 +1453,17 @@ nsHtml5StreamParser::ContinueAfterScript
       return;
     }
     nsHtml5Speculation* speculation = mSpeculations.ElementAt(0);
     if (aLastWasCR || 
         !aTokenizer->isInDataState() || 
         !aTreeBuilder->snapshotMatches(speculation->GetSnapshot())) {
       speculationFailed = true;
       // We've got a failed speculation :-(
+      MaybeDisableFutureSpeculation();
       Interrupt(); // Make the parser thread release the tokenizer mutex sooner
       // now fall out of the speculationAutoLock into the tokenizerAutoLock block
     } else {
       // We've got a successful speculation!
       if (mSpeculations.Length() > 1) {
         // the first speculation isn't the current speculation, so there's 
         // no need to bother the parser thread.
         speculation->FlushToSink(mExecutor);
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -358,16 +358,35 @@ class nsHtml5StreamParser : public nsICh
     static void TimerCallback(nsITimer* aTimer, void* aClosure);
 
     /**
      * Parser thread entry point for (maybe) flushing the ops and posting
      * a flush runnable back on the main thread.
      */
     void TimerFlush();
 
+    /**
+     * Called when speculation fails.
+     */
+    void MaybeDisableFutureSpeculation()
+    {
+        mSpeculationFailureCount++;
+    }
+
+    /**
+     * Used to check whether we're getting too many speculation failures and
+     * should just stop trying.  The 100 is picked pretty randomly to be not too
+     * small (so most pages are not affected) but small enough that we don't end
+     * up with failed speculations over and over in pathological cases.
+     */
+    bool IsSpeculationEnabled()
+    {
+        return mSpeculationFailureCount < 100;
+    }
+
     nsCOMPtr<nsIRequest>          mRequest;
     nsCOMPtr<nsIRequestObserver>  mObserver;
 
     /**
      * The document title to use if this turns out to be a View Source parser.
      */
     nsCString                     mViewSourceTitle;
 
@@ -480,16 +499,21 @@ class nsHtml5StreamParser : public nsICh
      * To access the queue of current speculation, mTokenizerMutex must be 
      * obtained.
      * The current speculation is the last element
      */
     nsTArray<nsAutoPtr<nsHtml5Speculation> >  mSpeculations;
     mozilla::Mutex                            mSpeculationMutex;
 
     /**
+     * Number of times speculation has failed for this parser.
+     */
+    uint32_t                      mSpeculationFailureCount;
+
+    /**
      * True to terminate early; protected by mTerminatedMutex
      */
     bool                          mTerminated;
     bool                          mInterrupted;
     mozilla::Mutex                mTerminatedMutex;
     
     /**
      * The thread this stream parser runs on.