Commit 6596856d authored by jianli@chromium.org's avatar jianli@chromium.org

Revert of HTMLConstructionSite: avoid n^2 running time for large scripts....

Revert of HTMLConstructionSite: avoid n^2 running time for large scripts. (patchset #5 id:80001 of https://codereview.chromium.org/494993002/)

Reason for revert:
Speculative revert.

It may break the following blink sheriff bot:
http://build.chromium.org/p/chromium.webkit/builders/Android%20Tests%20%28dbg%29/builds/21403



Original issue's description:
> HTMLConstructionSite: avoid n^2 running time for large scripts.
> 
> Every time background parser sends chunk, tree is flushed.
> 
> If page contains very large script, then script node content is updated
> many times. Every update is causes string concatenation.
> 
> Solution: do not flush pending text until it is mandatory.
> 
> Test: https://codereview.chromium.org/500363002
> Test depends on: https://codereview.chromium.org/544453004/
> 
> BUG=410790
> 
> Committed: https://src.chromium.org/viewvc/blink?view=rev&revision=181635

TBR=eseidel@chromium.org,kouhei@chromium.org,eustas@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=410790

Review URL: https://codereview.chromium.org/555223002

git-svn-id: svn://svn.chromium.org/blink/trunk@181664 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent eb7a3b16
...@@ -231,15 +231,11 @@ static String atomizeIfAllWhitespace(const String& string, WhitespaceMode whites ...@@ -231,15 +231,11 @@ static String atomizeIfAllWhitespace(const String& string, WhitespaceMode whites
return string; return string;
} }
void HTMLConstructionSite::flushPendingText(FlushMode mode) void HTMLConstructionSite::flushPendingText()
{ {
if (m_pendingText.isEmpty()) if (m_pendingText.isEmpty())
return; return;
if (mode == FlushIfAtTextLimit
&& !shouldUseLengthLimit(*m_pendingText.parent))
return;
PendingText pendingText; PendingText pendingText;
// Hold onto the current pending text on the stack so that queueTask doesn't recurse infinitely. // Hold onto the current pending text on the stack so that queueTask doesn't recurse infinitely.
m_pendingText.swap(pendingText); m_pendingText.swap(pendingText);
...@@ -273,7 +269,7 @@ void HTMLConstructionSite::flushPendingText(FlushMode mode) ...@@ -273,7 +269,7 @@ void HTMLConstructionSite::flushPendingText(FlushMode mode)
void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task) void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task)
{ {
flushPendingText(FlushAlways); flushPendingText();
ASSERT(m_pendingText.isEmpty()); ASSERT(m_pendingText.isEmpty());
m_taskQueue.append(task); m_taskQueue.append(task);
} }
...@@ -537,7 +533,7 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c ...@@ -537,7 +533,7 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c
void HTMLConstructionSite::processEndOfFile() void HTMLConstructionSite::processEndOfFile()
{ {
ASSERT(currentNode()); ASSERT(currentNode());
flush(FlushAlways); flush();
openElements()->popAll(); openElements()->popAll();
} }
...@@ -545,7 +541,7 @@ void HTMLConstructionSite::finishedParsing() ...@@ -545,7 +541,7 @@ void HTMLConstructionSite::finishedParsing()
{ {
// We shouldn't have any queued tasks but we might have pending text which we need to promote to tasks and execute. // We shouldn't have any queued tasks but we might have pending text which we need to promote to tasks and execute.
ASSERT(m_taskQueue.isEmpty()); ASSERT(m_taskQueue.isEmpty());
flush(FlushAlways); flush();
m_document->finishedParsing(); m_document->finishedParsing();
} }
...@@ -693,7 +689,7 @@ void HTMLConstructionSite::insertTextNode(const String& string, WhitespaceMode w ...@@ -693,7 +689,7 @@ void HTMLConstructionSite::insertTextNode(const String& string, WhitespaceMode w
// The nextChild != dummy.nextChild case occurs whenever foster parenting happened and we hit a new text node "<table>a</table>b" // The nextChild != dummy.nextChild case occurs whenever foster parenting happened and we hit a new text node "<table>a</table>b"
// In either case we have to flush the pending text into the task queue before making more. // In either case we have to flush the pending text into the task queue before making more.
if (!m_pendingText.isEmpty() && (m_pendingText.parent != dummyTask.parent || m_pendingText.nextChild != dummyTask.nextChild)) if (!m_pendingText.isEmpty() && (m_pendingText.parent != dummyTask.parent || m_pendingText.nextChild != dummyTask.nextChild))
flushPendingText(FlushAlways); flushPendingText();
m_pendingText.append(dummyTask.parent, dummyTask.nextChild, string, whitespaceMode); m_pendingText.append(dummyTask.parent, dummyTask.nextChild, string, whitespaceMode);
} }
......
...@@ -92,14 +92,6 @@ enum WhitespaceMode { ...@@ -92,14 +92,6 @@ enum WhitespaceMode {
AllWhitespace, AllWhitespace,
}; };
enum FlushMode {
// Flush pending text. Flush queued tasks.
FlushAlways,
// Flush pending text if node has length limit. Flush queued tasks.
FlushIfAtTextLimit,
};
class AtomicHTMLToken; class AtomicHTMLToken;
class Document; class Document;
class Element; class Element;
...@@ -121,16 +113,16 @@ public: ...@@ -121,16 +113,16 @@ public:
void executeQueuedTasks(); void executeQueuedTasks();
// flushPendingText turns pending text into queued Text insertions, but does not execute them. // flushPendingText turns pending text into queued Text insertions, but does not execute them.
void flushPendingText(FlushMode); void flushPendingText();
// Called before every token in HTMLTreeBuilder::processToken, thus inlined: // Called before every token in HTMLTreeBuilder::processToken, thus inlined:
void flush(FlushMode mode) void flush()
{ {
if (!hasPendingTasks()) if (!hasPendingTasks())
return; return;
flushPendingText(mode); flushPendingText();
executeQueuedTasks(); // NOTE: Possible reentrancy via JavaScript execution. executeQueuedTasks(); // NOTE: Possible reentrancy via JavaScript execution.
ASSERT(mode == FlushIfAtTextLimit || !hasPendingTasks()); ASSERT(!hasPendingTasks());
} }
bool hasPendingTasks() bool hasPendingTasks()
......
...@@ -498,10 +498,9 @@ void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse ...@@ -498,10 +498,9 @@ void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse
ASSERT(!m_token); ASSERT(!m_token);
} }
// Make sure all required pending text nodes are emitted before returning. // Make sure any pending text nodes are emitted before returning.
// This leaves "script", "style" and "svg" nodes text nodes intact.
if (!isStopped()) if (!isStopped())
m_treeBuilder->flush(FlushIfAtTextLimit); m_treeBuilder->flush();
} }
void HTMLDocumentParser::pumpPendingSpeculations() void HTMLDocumentParser::pumpPendingSpeculations()
...@@ -636,7 +635,7 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) ...@@ -636,7 +635,7 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
// There should only be PendingText left since the tree-builder always flushes // There should only be PendingText left since the tree-builder always flushes
// the task queue before returning. In case that ever changes, crash. // the task queue before returning. In case that ever changes, crash.
if (mode == ForceSynchronous) if (mode == ForceSynchronous)
m_treeBuilder->flush(FlushAlways); m_treeBuilder->flush();
RELEASE_ASSERT(!isStopped()); RELEASE_ASSERT(!isStopped());
if (session.needsYield) if (session.needsYield)
......
...@@ -402,7 +402,7 @@ void HTMLTreeBuilder::processToken(AtomicHTMLToken* token) ...@@ -402,7 +402,7 @@ void HTMLTreeBuilder::processToken(AtomicHTMLToken* token)
// Any non-character token needs to cause us to flush any pending text immediately. // Any non-character token needs to cause us to flush any pending text immediately.
// NOTE: flush() can cause any queued tasks to execute, possibly re-entering the parser. // NOTE: flush() can cause any queued tasks to execute, possibly re-entering the parser.
m_tree.flush(FlushAlways); m_tree.flush();
m_shouldSkipLeadingNewline = false; m_shouldSkipLeadingNewline = false;
switch (token->type()) { switch (token->type()) {
...@@ -2689,7 +2689,7 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) ...@@ -2689,7 +2689,7 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token)
return; return;
} }
m_tree.flush(FlushAlways); m_tree.flush();
HTMLStackItem* adjustedCurrentNode = adjustedCurrentStackItem(); HTMLStackItem* adjustedCurrentNode = adjustedCurrentStackItem();
switch (token->type()) { switch (token->type()) {
......
...@@ -82,9 +82,8 @@ public: ...@@ -82,9 +82,8 @@ public:
// Done, close any open tags, etc. // Done, close any open tags, etc.
void finished(); void finished();
// Synchronously flush pending text and queued tasks, possibly creating more DOM nodes. // Synchronously empty any queues, possibly creating more DOM nodes.
// Flushing pending text depends on |mode|. void flush() { m_tree.flush(); }
void flush(FlushMode mode) { m_tree.flush(mode); }
void setShouldSkipLeadingNewline(bool shouldSkip) { m_shouldSkipLeadingNewline = shouldSkip; } void setShouldSkipLeadingNewline(bool shouldSkip) { m_shouldSkipLeadingNewline = shouldSkip; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment