Changeset 89219 in webkit


Ignore:
Timestamp:
Jun 19, 2011 12:47:45 PM (13 years ago)
Author:
oliver@apple.com
Message:

2011-06-17 Oliver Hunt <oliver@apple.com>

Reviewed by Gavin Barraclough.

JSONP is unnecessarily slow
https://bugs.webkit.org/show_bug.cgi?id=62920

JSONP has unfortunately become a fairly common idiom online, yet
it triggers very poor performance in JSC as we end up doing codegen
for a large number of property accesses that will

  • only be run once, so the vast amount of logic we dump to handle caching of accesses is unnecessary.
  • We are doing codegen that is directly proportional to just creating the object in the first place.

This patch extends the use of the literal parser to JSONP-like structures
in global code, handling a number of different forms I have seen online.
In an extreme case this improves performance of JSONP by more than 2x
due to removal of code generation and execution time, and a few optimisations
that I made to the parser itself.

  • API/JSValueRef.cpp: (JSValueMakeFromJSONString):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::callEval): (JSC::Interpreter::execute):
  • parser/Lexer.cpp: (JSC::Lexer::isKeyword):
  • parser/Lexer.h:
  • runtime/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval):
  • runtime/JSONObject.cpp: (JSC::JSONProtoFuncParse):
  • runtime/LiteralParser.cpp: (JSC::LiteralParser::tryJSONPParse): (JSC::LiteralParser::makeIdentifier): (JSC::LiteralParser::Lexer::lex): (JSC::LiteralParser::Lexer::next): (JSC::isSafeStringCharacter): (JSC::LiteralParser::Lexer::lexString): (JSC::LiteralParser::Lexer::lexNumber): (JSC::LiteralParser::parse):
  • runtime/LiteralParser.h: (JSC::LiteralParser::LiteralParser): (JSC::LiteralParser::tryLiteralParse): (JSC::LiteralParser::Lexer::Lexer):
Location:
trunk/Source/JavaScriptCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/JSValueRef.cpp

    r89192 r89219  
    235235    ExecState* exec = toJS(ctx);
    236236    APIEntryShim entryShim(exec);
    237     LiteralParser parser(exec, string->ustring(), LiteralParser::StrictJSON);
     237    UString str = string->ustring();
     238    LiteralParser parser(exec, str.characters(), str.length(), LiteralParser::StrictJSON);
    238239    return toRef(exec, parser.tryLiteralParse());
    239240}
  • trunk/Source/JavaScriptCore/ChangeLog

    r89192 r89219  
     12011-06-17  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Gavin Barraclough.
     4
     5        JSONP is unnecessarily slow
     6        https://bugs.webkit.org/show_bug.cgi?id=62920
     7
     8        JSONP has unfortunately become a fairly common idiom online, yet
     9        it triggers very poor performance in JSC as we end up doing codegen
     10        for a large number of property accesses that will
     11           * only be run once, so the vast amount of logic we dump to handle
     12             caching of accesses is unnecessary.
     13           * We are doing codegen that is directly proportional to just
     14             creating the object in the first place.
     15
     16        This patch extends the use of the literal parser to JSONP-like structures
     17        in global code, handling a number of different forms I have seen online.
     18        In an extreme case this improves performance of JSONP by more than 2x
     19        due to removal of code generation and execution time, and a few optimisations
     20        that I made to the parser itself.
     21
     22        * API/JSValueRef.cpp:
     23        (JSValueMakeFromJSONString):
     24        * interpreter/Interpreter.cpp:
     25        (JSC::Interpreter::callEval):
     26        (JSC::Interpreter::execute):
     27        * parser/Lexer.cpp:
     28        (JSC::Lexer::isKeyword):
     29        * parser/Lexer.h:
     30        * runtime/JSGlobalObjectFunctions.cpp:
     31        (JSC::globalFuncEval):
     32        * runtime/JSONObject.cpp:
     33        (JSC::JSONProtoFuncParse):
     34        * runtime/LiteralParser.cpp:
     35        (JSC::LiteralParser::tryJSONPParse):
     36        (JSC::LiteralParser::makeIdentifier):
     37        (JSC::LiteralParser::Lexer::lex):
     38        (JSC::LiteralParser::Lexer::next):
     39        (JSC::isSafeStringCharacter):
     40        (JSC::LiteralParser::Lexer::lexString):
     41        (JSC::LiteralParser::Lexer::lexNumber):
     42        (JSC::LiteralParser::parse):
     43        * runtime/LiteralParser.h:
     44        (JSC::LiteralParser::LiteralParser):
     45        (JSC::LiteralParser::tryLiteralParse):
     46        (JSC::LiteralParser::Lexer::Lexer):
     47
    1482011-06-18  Sheriff Bot  <webkit.review.bot@gmail.com>
    249
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r89192 r89219  
    397397        // FIXME: We can use the preparser in strict mode, we just need additional logic
    398398        // to prevent duplicates.
    399         LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
     399        LiteralParser preparser(callFrame, programSource.characters(), programSource.length(), LiteralParser::NonStrictJSON);
    400400        if (JSValue parsedObject = preparser.tryLiteralParse())
    401401            return parsedObject;
     
    745745
    746746    DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
     747    LiteralParser literalParser(callFrame, program->source().data(), program->source().length(), LiteralParser::JSONP);
     748    Vector<LiteralParser::JSONPData> JSONPData;
     749    if (literalParser.tryJSONPParse(JSONPData)) {
     750        JSGlobalObject* globalObject = scopeChain->globalObject.get();
     751        JSValue result;
     752        for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
     753            Vector<LiteralParser::JSONPPathEntry> JSONPPath;
     754            JSONPPath.swap(JSONPData[entry].m_path);
     755            JSValue JSONPValue = JSONPData[entry].m_value.get();
     756            if (JSONPPath.size() == 1 && JSONPPath[0].m_type == LiteralParser::JSONPPathEntryTypeDeclare) {
     757                if (globalObject->hasProperty(callFrame, JSONPPath[0].m_pathEntryName)) {
     758                    PutPropertySlot slot;
     759                    globalObject->put(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
     760                } else
     761                    globalObject->putWithAttributes(callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, DontEnum | DontDelete);
     762                // var declarations return undefined
     763                result = jsUndefined();
     764                continue;
     765            }
     766            JSValue baseObject(globalObject);
     767            for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
     768                ASSERT(JSONPPath[i].m_type != LiteralParser::JSONPPathEntryTypeDeclare);
     769                switch (JSONPPath[i].m_type) {
     770                case LiteralParser::JSONPPathEntryTypeDot: {
     771                    if (i == 0) {
     772                        PropertySlot slot(globalObject);
     773                        if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot))
     774                            return throwError(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName));
     775                        baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
     776                    } else
     777                        baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
     778                    if (callFrame->hadException())
     779                        return jsUndefined();
     780                    continue;
     781                }
     782                case LiteralParser::JSONPPathEntryTypeLookup: {
     783                    baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
     784                    if (callFrame->hadException())
     785                        return jsUndefined();
     786                    continue;
     787                }
     788                default:
     789                    ASSERT_NOT_REACHED();
     790                    return jsUndefined();
     791                }
     792            }
     793            PutPropertySlot slot;
     794            switch (JSONPPath.last().m_type) {
     795            case LiteralParser::JSONPPathEntryTypeDot: {
     796                baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
     797                if (callFrame->hadException())
     798                    return jsUndefined();
     799                break;
     800            }
     801            case LiteralParser::JSONPPathEntryTypeLookup: {
     802                baseObject.put(callFrame, JSONPPath.last().m_pathIndex, JSONPValue);
     803                if (callFrame->hadException())
     804                    return jsUndefined();
     805                break;
     806            }
     807            default:
     808                ASSERT_NOT_REACHED();
     809                    return jsUndefined();
     810            }
     811            result = JSONPValue;
     812        }
     813        return result;
     814    }
    747815
    748816    JSObject* error = program->compile(callFrame, scopeChain);
  • trunk/Source/JavaScriptCore/parser/Lexer.cpp

    r89192 r89219  
    482482}
    483483
     484bool Lexer::isKeyword(const Identifier& ident)
     485{
     486    return m_keywordTable.entry(m_globalData, ident);
     487}
     488
    484489template <bool shouldBuildStrings> ALWAYS_INLINE bool Lexer::parseString(JSTokenData* tokenData, bool strictMode)
    485490{
  • trunk/Source/JavaScriptCore/parser/Lexer.h

    r89192 r89219  
    9191       
    9292        JSTokenType lexExpectIdentifier(JSTokenData*, JSTokenInfo*, unsigned, bool strictMode);
    93        
     93
     94        bool isKeyword(const Identifier&);
     95
    9496    private:
    9597        friend class JSGlobalData;
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r89192 r89219  
    446446    UString s = x.toString(exec);
    447447
    448     LiteralParser preparser(exec, s, LiteralParser::NonStrictJSON);
     448    LiteralParser preparser(exec, s.characters(), s.length(), LiteralParser::NonStrictJSON);
    449449    if (JSValue parsedObject = preparser.tryLiteralParse())
    450450        return JSValue::encode(parsedObject);
  • trunk/Source/JavaScriptCore/runtime/JSONObject.cpp

    r89192 r89219  
    817817
    818818    LocalScope scope(exec->globalData());
    819     LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON);
     819    LiteralParser jsonParser(exec, source.characters(), source.length(), LiteralParser::StrictJSON);
    820820    JSValue unfiltered = jsonParser.tryLiteralParse();
    821821    if (!unfiltered)
  • trunk/Source/JavaScriptCore/runtime/LiteralParser.cpp

    r89192 r89219  
    4343}
    4444
    45 LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
     45bool LiteralParser::tryJSONPParse(Vector<JSONPData>& results)
     46{
     47    if (m_lexer.next() != TokIdentifier)
     48        return false;
     49    do {
     50        Vector<JSONPPathEntry> path;
     51        // Unguarded next to start off the lexer
     52        Identifier name = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
     53        JSONPPathEntry entry;
     54        if (name == m_exec->globalData().propertyNames->varKeyword) {
     55            if (m_lexer.next() != TokIdentifier)
     56                return false;
     57            entry.m_type = JSONPPathEntryTypeDeclare;
     58            entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
     59            path.append(entry);
     60        } else {
     61            entry.m_type = JSONPPathEntryTypeDot;
     62            entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
     63            path.append(entry);
     64        }
     65        if (m_exec->globalData().lexer->isKeyword(entry.m_pathEntryName))
     66            return false;
     67        TokenType tokenType = m_lexer.next();
     68        while (tokenType != TokAssign) {
     69            switch (tokenType) {
     70            case TokLBracket: {
     71                entry.m_type = JSONPPathEntryTypeLookup;
     72                if (m_lexer.next() != TokNumber)
     73                    return false;
     74                double doubleIndex = m_lexer.currentToken().numberToken;
     75                int index = (int)doubleIndex;
     76                if (index != doubleIndex || index < 0)
     77                    return false;
     78                entry.m_pathIndex = index;
     79                if (m_lexer.next() != TokRBracket)
     80                    return false;
     81                break;
     82            }
     83            case TokDot: {
     84                entry.m_type = JSONPPathEntryTypeDot;
     85                if (m_lexer.next() != TokIdentifier)
     86                    return false;
     87                entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
     88                break;
     89            }
     90            default:
     91                return false;
     92            }
     93            path.append(entry);
     94            tokenType = m_lexer.next();
     95        }
     96        m_lexer.next();
     97        results.append(JSONPData());
     98        results.last().m_value.set(m_exec->globalData(), parse(StartParseExpression));
     99        if (!results.last().m_value)
     100            return false;
     101        results.last().m_path.swap(path);
     102        if (m_lexer.currentToken().type != TokSemi)
     103            break;
     104        m_lexer.next();
     105    } while (m_lexer.currentToken().type == TokIdentifier);
     106    return m_lexer.currentToken().type == TokEnd;
     107}
     108   
     109ALWAYS_INLINE const Identifier LiteralParser::makeIdentifier(const UChar* characters, size_t length)
     110{
     111    if (!length)
     112        return m_exec->globalData().propertyNames->emptyIdentifier;
     113    if (characters[0] >= MaximumCachableCharacter)
     114        return Identifier(&m_exec->globalData(), characters, length);
     115
     116    if (length == 1) {
     117        if (!m_shortIdentifiers[characters[0]].isNull())
     118            return m_shortIdentifiers[characters[0]];
     119        m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
     120        return m_shortIdentifiers[characters[0]];
     121    }
     122    if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
     123        return m_recentIdentifiers[characters[0]];
     124    m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
     125    return m_recentIdentifiers[characters[0]];
     126}
     127
     128template <LiteralParser::ParserMode mode> LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
    46129{
    47130    while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
     
    90173            return TokColon;
    91174        case '"':
    92             if (m_mode == StrictJSON)
    93                 return lexString<StrictJSON>(token);
    94             return lexString<NonStrictJSON>(token);
     175            return lexString<mode, '"'>(token);
    95176        case 't':
    96177            if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
     
    116197                return TokNull;
    117198            }
    118             break;   
     199            break;
    119200        case '-':
    120201        case '0':
     
    130211            return lexNumber(token);
    131212    }
     213    if (m_ptr < m_end) {
     214        if (*m_ptr == '.') {
     215            token.type = TokDot;
     216            token.end = ++m_ptr;
     217            return TokDot;
     218        }
     219        if (*m_ptr == '=') {
     220            token.type = TokAssign;
     221            token.end = ++m_ptr;
     222            return TokAssign;
     223        }
     224        if (*m_ptr == ';') {
     225            token.type = TokSemi;
     226            token.end = ++m_ptr;
     227            return TokAssign;
     228        }
     229        if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$') {
     230            while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$'))
     231                m_ptr++;
     232            token.stringToken = token.start;
     233            token.stringLength = m_ptr - token.start;
     234            token.type = TokIdentifier;
     235            token.end = m_ptr;
     236            return TokIdentifier;
     237        }
     238        if (*m_ptr == '\'') {
     239            if (mode == StrictJSON)
     240                return TokError;
     241            return lexString<mode, '\''>(token);
     242        }
     243    }
    132244    return TokError;
    133245}
    134246
    135 template <LiteralParser::ParserMode mode> static inline bool isSafeStringCharacter(UChar c)
    136 {
    137     return (c >= ' ' && (mode == LiteralParser::StrictJSON || c <= 0xff) && c != '\\' && c != '"') || c == '\t';
     247LiteralParser::TokenType LiteralParser::Lexer::next()
     248{
     249    if (m_mode == NonStrictJSON)
     250        return lex<NonStrictJSON>(m_currentToken);
     251    if (m_mode == JSONP)
     252        return lex<JSONP>(m_currentToken);
     253    return lex<StrictJSON>(m_currentToken);
     254}
     255
     256template <LiteralParser::ParserMode mode, UChar terminator> static inline bool isSafeStringCharacter(UChar c)
     257{
     258    return (c >= ' ' && (mode == LiteralParser::StrictJSON || c <= 0xff) && c != '\\' && c != terminator) || c == '\t';
    138259}
    139260
    140261// "inline" is required here to help WINSCW compiler resolve specialized argument in templated functions.
    141 template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token)
     262template <LiteralParser::ParserMode mode, UChar terminator> inline LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token)
    142263{
    143264    ++m_ptr;
    144     const UChar* runStart;
     265    const UChar* runStart = m_ptr;
    145266    UStringBuilder builder;
    146267    do {
    147268        runStart = m_ptr;
    148         while (m_ptr < m_end && isSafeStringCharacter<mode>(*m_ptr))
     269        while (m_ptr < m_end && isSafeStringCharacter<mode, terminator>(*m_ptr))
    149270            ++m_ptr;
    150         if (runStart < m_ptr)
     271        if (builder.length())
    151272            builder.append(runStart, m_ptr - runStart);
    152         if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
     273        if ((mode != NonStrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
     274            if (builder.isEmpty() && runStart < m_ptr)
     275                builder.append(runStart, m_ptr - runStart);
    153276            ++m_ptr;
    154277            if (m_ptr >= m_end)
     
    200323
    201324                default:
     325                    if (*m_ptr == '\'' && mode != StrictJSON) {
     326                        builder.append('\'');
     327                        m_ptr++;
     328                        break;
     329                    }
    202330                    return TokError;
    203331            }
    204332        }
    205     } while ((mode == StrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != '"');
    206 
    207     if (m_ptr >= m_end || *m_ptr != '"')
     333    } while ((mode != NonStrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != terminator);
     334
     335    if (m_ptr >= m_end || *m_ptr != terminator)
    208336        return TokError;
    209337
    210     token.stringToken = builder.toUString();
     338    if (builder.isEmpty()) {
     339        token.stringBuffer = UString();
     340        token.stringToken = runStart;
     341        token.stringLength = m_ptr - runStart;
     342    } else {
     343        token.stringBuffer = builder.toUString();
     344        token.stringToken = token.stringBuffer.characters();
     345        token.stringLength = token.stringBuffer.length();
     346    }
    211347    token.type = TokString;
    212348    token.end = ++m_ptr;
     
    254390        while (m_ptr < m_end && isASCIIDigit(*m_ptr))
    255391            ++m_ptr;
     392    } else if (m_ptr < m_end && (*m_ptr != 'e' && *m_ptr != 'E') && (m_ptr - token.start) < 10) {
     393        int result = 0;
     394        token.type = TokNumber;
     395        token.end = m_ptr;
     396        const UChar* digit = token.start;
     397        int negative = 1;
     398        if (*digit == '-') {
     399            negative = -1;
     400            digit++;
     401        }
     402       
     403        while (digit < m_ptr)
     404            result = result * 10 + (*digit++) - '0';
     405        result *= negative;
     406        token.numberToken = result;
     407        return TokNumber;
    256408    }
    257409
     
    338490
    339491                TokenType type = m_lexer.next();
    340                 if (type == TokString) {
     492                if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
    341493                    Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
    342494
     
    346498                   
    347499                    m_lexer.next();
    348                     identifierStack.append(Identifier(m_exec, identifierToken.stringToken));
     500                    identifierStack.append(makeIdentifier(identifierToken.stringToken, identifierToken.stringLength));
    349501                    stateStack.append(DoParseObjectEndExpression);
    350502                    goto startParseExpression;
    351                 } else if (type != TokRBrace)
     503                }
     504                if (type != TokRBrace)
    352505                    return JSValue();
    353506                m_lexer.next();
     
    359512            case DoParseObjectStartExpression: {
    360513                TokenType type = m_lexer.next();
    361                 if (type != TokString)
     514                if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier))
    362515                    return JSValue();
    363516                Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
     
    368521
    369522                m_lexer.next();
    370                 identifierStack.append(Identifier(m_exec, identifierToken.stringToken));
     523                identifierStack.append(makeIdentifier(identifierToken.stringToken, identifierToken.stringLength));
    371524                stateStack.append(DoParseObjectEndExpression);
    372525                goto startParseExpression;
     
    395548                        Lexer::LiteralParserToken stringToken = m_lexer.currentToken();
    396549                        m_lexer.next();
    397                         lastValue = jsString(m_exec, stringToken.stringToken);
     550                        lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken, stringToken.stringLength).ustring());
    398551                        break;
    399552                    }
  • trunk/Source/JavaScriptCore/runtime/LiteralParser.h

    r89192 r89219  
    2727#define LiteralParser_h
    2828
     29#include "Identifier.h"
    2930#include "JSGlobalObjectFunctions.h"
    3031#include "JSValue.h"
     
    3536    class LiteralParser {
    3637    public:
    37         typedef enum { StrictJSON, NonStrictJSON } ParserMode;
    38         LiteralParser(ExecState* exec, const UString& s, ParserMode mode)
     38        typedef enum { StrictJSON, NonStrictJSON, JSONP } ParserMode;
     39        LiteralParser(ExecState* exec, const UChar* characters, unsigned length, ParserMode mode)
    3940            : m_exec(exec)
    40             , m_lexer(s, mode)
     41            , m_lexer(characters, length, mode)
    4142            , m_mode(mode)
    4243        {
     
    4748            m_lexer.next();
    4849            JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement);
     50            if (m_lexer.currentToken().type == TokSemi)
     51                m_lexer.next();
    4952            if (m_lexer.currentToken().type != TokEnd)
    5053                return JSValue();
    5154            return result;
    5255        }
     56       
     57        enum JSONPPathEntryType {
     58            JSONPPathEntryTypeDeclare, // var pathEntryName = JSON
     59            JSONPPathEntryTypeDot, // <prior entries>.pathEntryName = JSON
     60            JSONPPathEntryTypeLookup // <prior entries>[pathIndex] = JSON
     61        };
     62
     63        struct JSONPPathEntry {
     64            JSONPPathEntryType m_type;
     65            Identifier m_pathEntryName;
     66            int m_pathIndex;
     67        };
     68
     69        struct JSONPData {
     70            Vector<JSONPPathEntry> m_path;
     71            Strong<Unknown> m_value;
     72        };
     73
     74        bool tryJSONPParse(Vector<JSONPData>&);
     75
    5376    private:
    5477        enum ParserState { StartParseObject, StartParseArray, StartParseExpression,
     
    5982                         TokString, TokIdentifier, TokNumber, TokColon,
    6083                         TokLParen, TokRParen, TokComma, TokTrue, TokFalse,
    61                          TokNull, TokEnd, TokError };
    62 
     84                         TokNull, TokEnd, TokDot, TokAssign, TokSemi, TokError };
     85       
    6386        class Lexer {
    6487        public:
     
    6790                const UChar* start;
    6891                const UChar* end;
    69                 UString stringToken;
    70                 double numberToken;
     92                UString stringBuffer;
     93                union {
     94                    double numberToken;
     95                    struct {
     96                        const UChar* stringToken;
     97                        int stringLength;
     98                    };
     99                };
    71100            };
    72             Lexer(const UString& s, ParserMode mode)
    73                 : m_string(s)
    74                 , m_mode(mode)
    75                 , m_ptr(s.characters())
    76                 , m_end(s.characters() + s.length())
     101            Lexer(const UChar* characters, unsigned length, ParserMode mode)
     102                : m_mode(mode)
     103                , m_ptr(characters)
     104                , m_end(characters + length)
    77105            {
    78106            }
    79107           
    80             TokenType next()
    81             {
    82                 return lex(m_currentToken);
    83             }
     108            TokenType next();
    84109           
    85110            const LiteralParserToken& currentToken()
     
    89114           
    90115        private:
    91             TokenType lex(LiteralParserToken&);
    92             template <ParserMode mode> TokenType lexString(LiteralParserToken&);
    93             TokenType lexNumber(LiteralParserToken&);
     116            template <ParserMode mode> TokenType lex(LiteralParserToken&);
     117            template <ParserMode mode, UChar terminator> ALWAYS_INLINE TokenType lexString(LiteralParserToken&);
     118            ALWAYS_INLINE TokenType lexNumber(LiteralParserToken&);
    94119            LiteralParserToken m_currentToken;
    95120            UString m_string;
     
    105130        LiteralParser::Lexer m_lexer;
    106131        ParserMode m_mode;
     132        static unsigned const MaximumCachableCharacter = 128;
     133        FixedArray<Identifier, MaximumCachableCharacter> m_shortIdentifiers;
     134        FixedArray<Identifier, MaximumCachableCharacter> m_recentIdentifiers;
     135        ALWAYS_INLINE const Identifier makeIdentifier(const UChar* characters, size_t length);
    107136    };
     137
    108138}
    109139
Note: See TracChangeset for help on using the changeset viewer.