Changeset 60739 in webkit


Ignore:
Timestamp:
Jun 4, 2010 11:57:54 PM (14 years ago)
Author:
abarth@webkit.org
Message:

2010-06-04 Adam Barth <abarth@webkit.org>

Reviewed by Eric Seidel.

Make HTML5Lexer go fast
https://bugs.webkit.org/show_bug.cgi?id=40048

This patch changes us from using a jump table for each character to
using absolute jumps between parser states. This appears to be about a
1% improvement on the parser bench mark (which is 1/10th of what we
need to catch the old parser).

I've kept the underlying logic as close to the old logic as possible.
This new form will make it easier to handle the input stream part of
the spec and to make further performance improvements.

  • html/HTML5Lexer.cpp: (WebCore::HTML5Lexer::reset): (WebCore::HTML5Lexer::nextToken): (WebCore::HTML5Lexer::emitCurrentToken):
  • html/HTML5Lexer.h:
Location:
trunk/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r60738 r60739  
     12010-06-04  Adam Barth  <abarth@webkit.org>
     2
     3        Reviewed by Eric Seidel.
     4
     5        Make HTML5Lexer go fast
     6        https://bugs.webkit.org/show_bug.cgi?id=40048
     7
     8        This patch changes us from using a jump table for each character to
     9        using absolute jumps between parser states.  This appears to be about a
     10        1% improvement on the parser bench mark (which is 1/10th of what we
     11        need to catch the old parser).
     12
     13        I've kept the underlying logic as close to the old logic as possible.
     14        This new form will make it easier to handle the input stream part of
     15        the spec and to make further performance improvements.
     16
     17        * html/HTML5Lexer.cpp:
     18        (WebCore::HTML5Lexer::reset):
     19        (WebCore::HTML5Lexer::nextToken):
     20        (WebCore::HTML5Lexer::emitCurrentToken):
     21        * html/HTML5Lexer.h:
     22
    1232010-06-04  Adam Barth  <abarth@webkit.org>
    224
  • trunk/WebCore/html/HTML5Lexer.cpp

    r60738 r60739  
    157157    m_lineNumber = 0;
    158158    m_skipLeadingNewLineForListing = false;
    159     m_emitPending = false;
    160159    m_additionalAllowedCharacter = '\0';
    161160}
     
    325324#endif
    326325
    327 #define BEGIN_STATE(stateName) case stateName:
     326#define BEGIN_STATE(stateName) case stateName: stateName:
    328327#define END_STATE() ASSERT_NOT_REACHED(); break;
    329328
    330 #define EMIT_AND_RESUME_IN(stateName)                                       \
    331     do {                                                                    \
    332         emitCurrentToken();                                                 \
    333         m_state = DataState;                                                \
    334         goto breakLabel;                                                    \
     329#define RECONSUME_IN(stateName)                                            \
     330    do {                                                                   \
     331        m_state = stateName;                                               \
     332        cc = *source;                                                      \
     333        goto stateName;                                                    \
    335334    } while (false)
    336335
    337 #define ADVANCE_TO(stateName)                                               \
    338     do {                                                                    \
    339         m_state = stateName;                                                \
    340         goto breakLabel;                                                    \
     336#define ADVANCE_TO(stateName)                                              \
     337    do {                                                                   \
     338        m_state = stateName;                                               \
     339        source.advance(m_lineNumber);                                      \
     340        if (source.isEmpty())                                              \
     341            return shouldEmitBufferedCharacterToken(source);               \
     342        cc = *source;                                                      \
     343        goto stateName;                                                    \
    341344    } while (false)
    342345
    343 #define RECONSUME_IN(stateName)                                             \
    344     do {                                                                    \
    345         m_state = stateName;                                                \
    346         goto continueLabel;                                                 \
     346#define EMIT_AND_RESUME_IN(stateName)                                      \
     347    do {                                                                   \
     348        m_state = stateName;                                               \
     349        source.advance(m_lineNumber);                                      \
     350        emitCurrentToken();                                                \
     351        return true;                                                       \
    347352    } while (false)
    348353
    349 #define FLUSH_EMIT_AND_RESUME_IN(stateName)                                 \
    350     do {                                                                    \
    351         m_state = stateName;                                                \
    352         maybeFlushBufferedEndTag();                                         \
    353         goto breakLabel;                                                    \
     354#define _FLUSH_BUFFERED_END_TAG()                                          \
     355    do {                                                                   \
     356        ASSERT(m_token->type() == HTML5Token::Character ||                 \
     357               m_token->type() == HTML5Token::Uninitialized);              \
     358        source.advance(m_lineNumber);                                      \
     359        if (m_token->type() == HTML5Token::Character)                      \
     360            return true;                                                   \
     361        m_token->beginEndTag(m_bufferedEndTagName);                        \
     362        m_bufferedEndTagName.clear();                                      \
    354363    } while (false)
    355364
    356 // When we move away from using a jump table, these macros will be different.
    357 #define FLUSH_AND_ADVANCE_TO(stateName) FLUSH_EMIT_AND_RESUME_IN(stateName)
     365#define FLUSH_AND_ADVANCE_TO(stateName)                                    \
     366    do {                                                                   \
     367        m_state = stateName;                                               \
     368        _FLUSH_BUFFERED_END_TAG();                                         \
     369        if (source.isEmpty())                                              \
     370            return shouldEmitBufferedCharacterToken(source);               \
     371        cc = *source;                                                      \
     372        goto stateName;                                                    \
     373    } while (false)
     374
     375#define FLUSH_EMIT_AND_RESUME_IN(stateName)                                \
     376    do {                                                                   \
     377        m_state = stateName;                                               \
     378        _FLUSH_BUFFERED_END_TAG();                                         \
     379        return true;                                                       \
     380    } while (false)
    358381
    359382bool HTML5Lexer::nextToken(SegmentedString& source, HTML5Token& token)
     
    380403    m_skipLeadingNewLineForListing = false;
    381404
     405    if (source.isEmpty())
     406        return shouldEmitBufferedCharacterToken(source);
     407
    382408    // Source: http://www.whatwg.org/specs/web-apps/current-work/#tokenisation0
    383     // FIXME: This while should stop as soon as we have a token to return.
    384     while (!source.isEmpty()) {
    385     // FIXME: This is a purposeful style violation because this while loop is
    386     // going to be removed soon.
    387 
    388409    UChar cc = *source;
    389410    switch (m_state) {
     
    11181139
    11191140    BEGIN_STATE(BogusCommentState) {
     1141        // FIXME: This state isn't correct because we'll terminate the
     1142        // comment early if we don't have the whole input stream available.
    11201143        m_token->beginComment();
    11211144        while (!source.isEmpty()) {
    11221145            cc = *source;
    11231146            if (cc == '>')
    1124                 break;
     1147                EMIT_AND_RESUME_IN(DataState);
    11251148            m_token->appendToComment(cc);
    11261149            source.advance(m_lineNumber);
    11271150        }
    1128         EMIT_AND_RESUME_IN(DataState);
    1129         if (source.isEmpty())
    1130             return true;
    1131         // FIXME: Handle EOF properly.
    1132         break;
     1151        m_state = DataState;
     1152        return true;
     1153        // FIXME: Handle EOF properly.
    11331154    }
    11341155    END_STATE()
     
    15771598    }
    15781599
    1579 breakLabel:
    1580     source.advance(m_lineNumber);
    1581     if (m_emitPending) {
    1582         m_emitPending = false;
    1583         return true;
    1584     }
    1585 
    1586 continueLabel:
    1587     ; // We need an empty statement here to make continueLabel happy.
    1588     } // Matches the "while" above.
    1589 
    1590     // We've reached the end of the input stream.  If we have a character
    1591     // token buffered, we should emit it.
    1592     return shouldEmitBufferedCharacterToken(source);
     1600    ASSERT_NOT_REACHED();
     1601    return false;
    15931602}
    15941603
     
    16331642}
    16341643
    1635 inline void HTML5Lexer::maybeFlushBufferedEndTag()
    1636 {
    1637     ASSERT(m_token->type() == HTML5Token::Character || m_token->type() == HTML5Token::Uninitialized);
    1638     if (m_token->type() == HTML5Token::Character) {
    1639         // We have a character token queued up.  We need to emit it before we
    1640         // can start begin the buffered end tag token.
    1641         emitCurrentToken();
    1642         return;
    1643     }
    1644     flushBufferedEndTag();
    1645 }
    1646 
    1647 inline void HTML5Lexer::flushBufferedEndTag()
    1648 {
    1649     m_token->beginEndTag(m_bufferedEndTagName);
    1650     m_bufferedEndTagName.clear();
    1651     if (m_state == DataState)
    1652         emitCurrentToken();
    1653 }
    1654 
    16551644inline void HTML5Lexer::emitCurrentToken()
    16561645{
    16571646    ASSERT(m_token->type() != HTML5Token::Uninitialized);
    1658     m_emitPending = true;
    16591647    if (m_token->type() == HTML5Token::StartTag)
    16601648        m_appropriateEndTagName = m_token->name();
  • trunk/WebCore/html/HTML5Lexer.h

    r60738 r60739  
    146146        inline void addToPossibleEndTag(UChar cc);
    147147        inline bool isAppropriateEndTag();
    148         inline void maybeFlushBufferedEndTag();
    149         inline void flushBufferedEndTag();
    150148
    151149        inline bool shouldEmitBufferedCharacterToken(const SegmentedString&);
     
    161159
    162160        bool m_skipLeadingNewLineForListing;
    163         bool m_emitPending;
    164161
    165162        // http://www.whatwg.org/specs/web-apps/current-work/#temporary-buffer
Note: See TracChangeset for help on using the changeset viewer.