Changeset 147383 in webkit


Ignore:
Timestamp:
Apr 1, 2013 10:34:38 PM (11 years ago)
Author:
abarth@webkit.org
Message:

Assertion failure !m_lastChunkBeforeScript in HTMLDocumentParser during inspector/debugger/pause-in-inline-script.html
https://bugs.webkit.org/show_bug.cgi?id=112369

Reviewed by Eric Seidel.

Source/WebCore:

The threaded HTML parser wasn't correctly handling the nested event
loops that can arise from the JavaScript debugger and from
showModalDialog. When the parser received a chunk from the background
parser, it was always processing it immediately, which lead to
re-entrancy. Now, we'll queue the chunk in the speculation buffer and
process it once the stack unwinds.

  • html/parser/HTMLDocumentParser.cpp:

(WebCore::HTMLDocumentParser::~HTMLDocumentParser):
(WebCore::HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser):
(WebCore::HTMLDocumentParser::processParsedChunkFromBackgroundParser):
(WebCore::HTMLDocumentParser::pumpPendingSpeculations):
(WebCore::HTMLDocumentParser::insert):

  • html/parser/HTMLParserScheduler.cpp:

(WebCore::PumpSession::PumpSession):

  • html/parser/HTMLParserScheduler.h:

LayoutTests:

Unskip test that is now passing.

  • platform/chromium/TestExpectations:
Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r147382 r147383  
     12013-04-01  Adam Barth  <abarth@webkit.org>
     2
     3        Assertion failure !m_lastChunkBeforeScript in HTMLDocumentParser during inspector/debugger/pause-in-inline-script.html
     4        https://bugs.webkit.org/show_bug.cgi?id=112369
     5
     6        Reviewed by Eric Seidel.
     7
     8        Unskip test that is now passing.
     9
     10        * platform/chromium/TestExpectations:
     11
    1122013-04-01  Michael Pruett  <michael@68k.org>
    213
  • trunk/LayoutTests/platform/chromium/TestExpectations

    r147380 r147383  
    37843784webkit.org/b/91611 media/media-higher-prio-audio-stream.html [ Skip ]
    37853785
    3786 # Flaky assertion failures on debug bots
    3787 webkit.org/b/112369 [ Debug ] inspector/debugger/pause-in-inline-script.html [ Pass Crash Timeout ]
    3788 
    37893786# Needs rebaseline on all platforms
    37903787Bug(leviw) fast/text/shaping/shaping-selection-rect.html [ Failure ]
  • trunk/Source/WebCore/ChangeLog

    r147382 r147383  
     12013-04-01  Adam Barth  <abarth@webkit.org>
     2
     3        Assertion failure !m_lastChunkBeforeScript in HTMLDocumentParser during inspector/debugger/pause-in-inline-script.html
     4        https://bugs.webkit.org/show_bug.cgi?id=112369
     5
     6        Reviewed by Eric Seidel.
     7
     8        The threaded HTML parser wasn't correctly handling the nested event
     9        loops that can arise from the JavaScript debugger and from
     10        showModalDialog. When the parser received a chunk from the background
     11        parser, it was always processing it immediately, which lead to
     12        re-entrancy. Now, we'll queue the chunk in the speculation buffer and
     13        process it once the stack unwinds.
     14
     15        * html/parser/HTMLDocumentParser.cpp:
     16        (WebCore::HTMLDocumentParser::~HTMLDocumentParser):
     17        (WebCore::HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser):
     18        (WebCore::HTMLDocumentParser::processParsedChunkFromBackgroundParser):
     19        (WebCore::HTMLDocumentParser::pumpPendingSpeculations):
     20        (WebCore::HTMLDocumentParser::insert):
     21        * html/parser/HTMLParserScheduler.cpp:
     22        (WebCore::PumpSession::PumpSession):
     23        * html/parser/HTMLParserScheduler.h:
     24
    1252013-04-01  Michael Pruett  <michael@68k.org>
    226
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp

    r146264 r147383  
    128128    ASSERT(!m_insertionPreloadScanner);
    129129    ASSERT(!m_haveBackgroundParser);
     130    // FIXME: We should be able to ASSERT(m_speculations.isEmpty()),
     131    // but there are cases where that's not true currently. For example,
     132    // we we're told to stop parsing before we've consumed all the input.
    130133}
    131134
     
    312315void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> chunk)
    313316{
    314     if (isWaitingForScripts() || !m_speculations.isEmpty()) {
     317    // alert(), runModalDialog, and the JavaScript Debugger all run nested event loops
     318    // which can cause this method to be re-entered. We detect re-entry using
     319    // inPumpSession(), save the chunk as a speculation, and return.
     320    if (isWaitingForScripts() || !m_speculations.isEmpty() || inPumpSession()) {
    315321        m_preloader->takeAndPreload(chunk->preloads);
    316322        m_speculations.append(chunk);
     
    322328    RefPtr<HTMLDocumentParser> protect(this);
    323329
    324     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), lineNumber().zeroBasedInt());
    325 
    326330    ASSERT(m_speculations.isEmpty());
    327331    chunk->preloads.clear(); // We don't need to preload because we're going to parse immediately.
    328     processParsedChunkFromBackgroundParser(chunk);
    329 
    330     InspectorInstrumentation::didWriteHTML(cookie, lineNumber().zeroBasedInt());
     332    m_speculations.append(chunk);
     333    pumpPendingSpeculations();
    331334}
    332335
     
    391394void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> popChunk)
    392395{
     396    ASSERT_WITH_SECURITY_IMPLICATION(!inPumpSession());
     397    ASSERT(!isParsingFragment());
     398    ASSERT(!isWaitingForScripts());
     399    ASSERT(!isStopped());
    393400    // ASSERT that this object is both attached to the Document and protected.
    394401    ASSERT(refCount() >= 2);
     
    398405    ASSERT(!m_lastChunkBeforeScript);
    399406
    400     ActiveParserSession session(contextForParsingSession());
     407    PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
     408
    401409    OwnPtr<ParsedChunk> chunk(popChunk);
    402410    OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release();
     
    427435            // we peek to see if this chunk has an EOF and process it anyway.
    428436            if (tokens->last().type() == HTMLToken::EndOfFile) {
    429                 ASSERT(m_speculations.isEmpty());
     437                ASSERT(m_speculations.isEmpty()); // There should never be any chunks after the EOF.
    430438                prepareToStopParsing();
    431439            }
     
    442450        if (it->type() == HTMLToken::EndOfFile) {
    443451            ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the last token of this bunch.
    444             ASSERT(m_speculations.isEmpty());
     452            ASSERT(m_speculations.isEmpty()); // There should never be any chunks after the EOF.
    445453            prepareToStopParsing();
    446454            break;
     
    464472    ASSERT(!m_token);
    465473    ASSERT(!m_lastChunkBeforeScript);
     474    ASSERT(!isWaitingForScripts());
     475    ASSERT(!isStopped());
    466476
    467477    // FIXME: Pass in current input length.
     
    630640#if ENABLE(THREADED_HTML_PARSER)
    631641    if (!m_tokenizer) {
    632         ASSERT(!inPumpSession());
    633642        ASSERT(m_haveBackgroundParser || wasCreatedByScript());
    634643        m_token = adoptPtr(new HTMLToken);
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.cpp

    r143845 r147383  
    7878
    7979PumpSession::PumpSession(unsigned& nestingLevel, Document* document)
    80     : NestingLevelIncrementer(nestingLevel)
    81     , ActiveParserSession(document)
     80    : ActiveParserSession(document)
     81    , NestingLevelIncrementer(nestingLevel)
    8282    // Setting processedTokens to INT_MAX causes us to check for yields
    8383    // after any token during any parse where yielding is allowed.
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.h

    r142378 r147383  
    4848};
    4949
    50 class PumpSession : public NestingLevelIncrementer, public ActiveParserSession {
     50// In C++, base classes are destructed from right to left, which means
     51// ~NestingLevelIncrementer will run before ~ActiveParserSession. This
     52// is important because ~ActiveParserSession calls Document::decrementActiveParserCount,
     53// which cares about the pump nesting level of the parser.
     54class PumpSession : public ActiveParserSession, public NestingLevelIncrementer {
    5155public:
    5256    PumpSession(unsigned& nestingLevel, Document*);
Note: See TracChangeset for help on using the changeset viewer.