Ignore:
Timestamp:
Aug 30, 2010, 1:24:40 AM (15 years ago)
Author:
[email protected]
Message:

Refactor number parsing in the lexer
https://bugs.webkit.org/show_bug.cgi?id=44104

Reviewed by Darin Adler.

Number parsing was full of gotos, and needed a complete
redesign to remove them (Only one remained). Furthermore
integer arithmetic is empolyed for fast cases (= small
integer numbers).

  • parser/Lexer.cpp:

(JSC::Lexer::parseHex):
(JSC::Lexer::parseOctal):
(JSC::Lexer::parseDecimal):
(JSC::Lexer::parseNumberAfterDecimalPoint):
(JSC::Lexer::parseNumberAfterExponentIndicator):
(JSC::Lexer::lex):

  • parser/Lexer.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/parser/Lexer.cpp

    r66135 r66375  
    536536}
    537537
     538ALWAYS_INLINE void Lexer::parseHex(double& returnValue)
     539{
     540    // Optimization: most hexadecimal values fit into 4 bytes.
     541    uint32_t hexValue = 0;
     542    int maximumDigits = 7;
     543
     544    // Shift out the 'x' prefix.
     545    shift();
     546
     547    do {
     548        hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
     549        shift();
     550        --maximumDigits;
     551    } while (isASCIIHexDigit(m_current) && maximumDigits >= 0);
     552
     553    if (maximumDigits >= 0) {
     554        returnValue = hexValue;
     555        return;
     556    }
     557
     558    // No more place in the hexValue buffer.
     559    // The values are shifted out and placed into the m_buffer8 vector.
     560    for (int i = 0; i < 8; ++i) {
     561         int digit = hexValue >> 28;
     562         if (digit < 10)
     563             record8(digit + '0');
     564         else
     565             record8(digit - 10 + 'a');
     566         hexValue <<= 4;
     567    }
     568
     569    while (isASCIIHexDigit(m_current)) {
     570        record8(m_current);
     571        shift();
     572    }
     573
     574    returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);
     575}
     576
     577ALWAYS_INLINE bool Lexer::parseOctal(double& returnValue)
     578{
     579    // Optimization: most octal values fit into 4 bytes.
     580    uint32_t octalValue = 0;
     581    int maximumDigits = 9;
     582    // Temporary buffer for the digits. Makes easier
     583    // to reconstruct the input characters when needed.
     584    char digits[10];
     585
     586    do {
     587        octalValue = octalValue * 8 + (m_current - '0');
     588        digits[maximumDigits] = m_current;
     589        shift();
     590        --maximumDigits;
     591    } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0);
     592
     593    if (!isASCIIDigit(m_current) && maximumDigits >= 0) {
     594        returnValue = octalValue;
     595        return true;
     596    }
     597
     598    for (int i = 9; i > maximumDigits; --i)
     599         record8(digits[i]);
     600
     601    while (isASCIIOctalDigit(m_current)) {
     602        record8(m_current);
     603        shift();
     604    }
     605
     606    if (isASCIIDigit(m_current))
     607        return false;
     608
     609    returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8);
     610    return true;
     611}
     612
     613ALWAYS_INLINE bool Lexer::parseDecimal(double& returnValue)
     614{
     615    // Optimization: most decimal values fit into 4 bytes.
     616    uint32_t decimalValue = 0;
     617
     618    // Since parseOctal may be executed before parseDecimal,
     619    // the m_buffer8 may hold ascii digits.
     620    if (!m_buffer8.size()) {
     621        int maximumDigits = 9;
     622        // Temporary buffer for the digits. Makes easier
     623        // to reconstruct the input characters when needed.
     624        char digits[10];
     625
     626        do {
     627            decimalValue = decimalValue * 10 + (m_current - '0');
     628            digits[maximumDigits] = m_current;
     629            shift();
     630            --maximumDigits;
     631        } while (isASCIIDigit(m_current) && maximumDigits >= 0);
     632
     633        if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
     634            returnValue = decimalValue;
     635            return true;
     636        }
     637
     638        for (int i = 9; i > maximumDigits; --i)
     639            record8(digits[i]);
     640    }
     641
     642    while (isASCIIDigit(m_current)) {
     643        record8(m_current);
     644        shift();
     645    }
     646
     647    return false;
     648}
     649
     650ALWAYS_INLINE void Lexer::parseNumberAfterDecimalPoint()
     651{
     652    record8('.');
     653    while (isASCIIDigit(m_current)) {
     654        record8(m_current);
     655        shift();
     656    }
     657}
     658
     659ALWAYS_INLINE bool Lexer::parseNumberAfterExponentIndicator()
     660{
     661    record8('e');
     662    shift();
     663    if (m_current == '+' || m_current == '-') {
     664        record8(m_current);
     665        shift();
     666    }
     667
     668    if (!isASCIIDigit(m_current))
     669        return false;
     670
     671    do {
     672        record8(m_current);
     673        shift();
     674    } while (isASCIIDigit(m_current));
     675    return true;
     676}
     677
    538678JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType lexType)
    539679{
     
    751891        token = BITOR;
    752892        break;
    753     case CharacterDot:
    754         shift();
    755         if (isASCIIDigit(m_current)) {
    756             record8('.');
    757             goto inNumberAfterDecimalPoint;
    758         }
    759         token = DOT;
    760         break;
    761893    case CharacterOpenParen:
    762894        token = OPENPAREN;
     
    807939        token = CLOSEBRACE;
    808940        break;
     941    case CharacterDot:
     942        shift();
     943        if (!isASCIIDigit(m_current)) {
     944            token = DOT;
     945            break;
     946        }
     947        goto inNumberAfterDecimalPoint;
    809948    case CharacterZero:
    810         goto startNumberWithZeroDigit;
     949        shift();
     950        if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) {
     951            parseHex(lvalp->doubleValue);
     952            token = NUMBER;
     953        } else {
     954            record8('0');
     955            if (isASCIIOctalDigit(m_current)) {
     956                if (parseOctal(lvalp->doubleValue))
     957                    token = NUMBER;
     958            }
     959        }
     960        // Fall through into CharacterNumber
    811961    case CharacterNumber:
    812         goto startNumber;
     962        if (LIKELY(token != NUMBER)) {
     963            if (!parseDecimal(lvalp->doubleValue)) {
     964                if (m_current == '.') {
     965                    shift();
     966inNumberAfterDecimalPoint:
     967                    parseNumberAfterDecimalPoint();
     968                }
     969                if ((m_current | 0x20) == 'e')
     970                    if (!parseNumberAfterExponentIndicator())
     971                        goto returnError;
     972                // Null-terminate string for strtod.
     973                m_buffer8.append('\0');
     974                lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0);
     975            }
     976            token = NUMBER;
     977        }
     978
     979        // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
     980        if (UNLIKELY(isIdentStart(m_current)))
     981            goto returnError;
     982        m_buffer8.resize(0);
     983        m_delimited = false;
     984        break;
    813985    case CharacterQuote:
    814986        if (UNLIKELY(!parseString(lvalp)))
     
    8781050    goto start;
    8791051
    880 startNumberWithZeroDigit:
    881     shift();
    882     if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) {
    883         shift();
    884         goto inHex;
    885     }
    886     if (m_current == '.') {
    887         record8('0');
    888         record8('.');
    889         shift();
    890         goto inNumberAfterDecimalPoint;
    891     }
    892     if ((m_current | 0x20) == 'e') {
    893         record8('0');
    894         record8('e');
    895         shift();
    896         goto inExponentIndicator;
    897     }
    898     if (isASCIIOctalDigit(m_current))
    899         goto inOctal;
    900     if (isASCIIDigit(m_current))
    901         goto startNumber;
    902     lvalp->doubleValue = 0;
    903     goto doneNumeric;
    904 
    905 inNumberAfterDecimalPoint:
    906     while (isASCIIDigit(m_current)) {
    907         record8(m_current);
    908         shift();
    909     }
    910     if ((m_current | 0x20) == 'e') {
    911         record8('e');
    912         shift();
    913         goto inExponentIndicator;
    914     }
    915     goto doneNumber;
    916 
    917 inExponentIndicator:
    918     if (m_current == '+' || m_current == '-') {
    919         record8(m_current);
    920         shift();
    921     }
    922     if (!isASCIIDigit(m_current))
    923         goto returnError;
    924     do {
    925         record8(m_current);
    926         shift();
    927     } while (isASCIIDigit(m_current));
    928     goto doneNumber;
    929 
    930 inOctal: {
    931     do {
    932         record8(m_current);
    933         shift();
    934     } while (isASCIIOctalDigit(m_current));
    935     if (isASCIIDigit(m_current))
    936         goto startNumber;
    937 
    938     double dval = 0;
    939 
    940     const char* end = m_buffer8.end();
    941     for (const char* p = m_buffer8.data(); p < end; ++p) {
    942         dval *= 8;
    943         dval += *p - '0';
    944     }
    945     if (dval >= mantissaOverflowLowerBound)
    946         dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 8);
    947 
    948     m_buffer8.resize(0);
    949 
    950     lvalp->doubleValue = dval;
    951     goto doneNumeric;
    952 }
    953 
    954 inHex: {
    955     do {
    956         record8(m_current);
    957         shift();
    958     } while (isASCIIHexDigit(m_current));
    959 
    960     double dval = 0;
    961 
    962     const char* end = m_buffer8.end();
    963     for (const char* p = m_buffer8.data(); p < end; ++p) {
    964         dval *= 16;
    965         dval += toASCIIHexValue(*p);
    966     }
    967     if (dval >= mantissaOverflowLowerBound)
    968         dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 16);
    969 
    970     m_buffer8.resize(0);
    971 
    972     lvalp->doubleValue = dval;
    973     goto doneNumeric;
    974 }
    975 
    976 startNumber:
    977     record8(m_current);
    978     shift();
    979     while (isASCIIDigit(m_current)) {
    980         record8(m_current);
    981         shift();
    982     }
    983     if (m_current == '.') {
    984         record8('.');
    985         shift();
    986         goto inNumberAfterDecimalPoint;
    987     }
    988     if ((m_current | 0x20) == 'e') {
    989         record8('e');
    990         shift();
    991         goto inExponentIndicator;
    992     }
    993 
    994     // Fall through into doneNumber.
    995 
    996 doneNumber:
    997     // Null-terminate string for strtod.
    998     m_buffer8.append('\0');
    999     lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0);
    1000     m_buffer8.resize(0);
    1001 
    1002     // Fall through into doneNumeric.
    1003 
    1004 doneNumeric:
    1005     // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
    1006     if (UNLIKELY(isIdentStart(m_current)))
    1007         goto returnError;
    1008 
    1009     m_atLineStart = false;
    1010     m_delimited = false;
    1011     token = NUMBER;
    1012     goto returnToken;
    1013 
    10141052doneSemicolon:
    10151053    token = SEMICOLON;
Note: See TracChangeset for help on using the changeset viewer.