Changeset 87177 in webkit


Ignore:
Timestamp:
May 24, 2011 11:49:18 AM (13 years ago)
Author:
oliver@apple.com
Message:

2011-05-24 Oliver Hunt <oliver@apple.com>

Reviewed by Geoffrey Garen.

Avoid creating unnecessary identifiers and strings in the syntax checker
https://bugs.webkit.org/show_bug.cgi?id=61378

Selectively tell the lexer that there are some places it does not need to
do the real work of creating Identifiers for IDENT and STRING tokens.

Make parseString and parseIdentifier templatized on whether they should
do real work, or merely validate the tokens.

SunSpider --parse-only reports ~5-8% win depending on hardware.

  • parser/ASTBuilder.h: (JSC::ASTBuilder::createDotAccess):
  • parser/JSParser.cpp: (JSC::JSParser::next): (JSC::JSParser::consume): (JSC::JSParser::parseVarDeclarationList): (JSC::JSParser::parseConstDeclarationList): (JSC::JSParser::parseExpression): (JSC::JSParser::parseAssignmentExpression): (JSC::JSParser::parseConditionalExpression): (JSC::JSParser::parseBinaryExpression): (JSC::JSParser::parseProperty): (JSC::JSParser::parseObjectLiteral): (JSC::JSParser::parseArrayLiteral): (JSC::JSParser::parseArguments): (JSC::JSParser::parseMemberExpression):
  • parser/Lexer.cpp: (JSC::Lexer::parseIdentifier): (JSC::Lexer::parseString): (JSC::Lexer::lex):
  • parser/Lexer.h:
  • parser/SyntaxChecker.h: (JSC::SyntaxChecker::createDotAccess): (JSC::SyntaxChecker::createProperty):
Location:
trunk/Source/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r87157 r87177  
     12011-05-24  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Geoffrey Garen.
     4
     5        Avoid creating unnecessary identifiers and strings in the syntax checker
     6        https://bugs.webkit.org/show_bug.cgi?id=61378
     7
     8        Selectively tell the lexer that there are some places it does not need to
     9        do the real work of creating Identifiers for IDENT and STRING tokens.
     10
     11        Make parseString and parseIdentifier templatized on whether they should
     12        do real work, or merely validate the tokens.
     13
     14        SunSpider --parse-only reports ~5-8% win depending on hardware.
     15
     16        * parser/ASTBuilder.h:
     17        (JSC::ASTBuilder::createDotAccess):
     18        * parser/JSParser.cpp:
     19        (JSC::JSParser::next):
     20        (JSC::JSParser::consume):
     21        (JSC::JSParser::parseVarDeclarationList):
     22        (JSC::JSParser::parseConstDeclarationList):
     23        (JSC::JSParser::parseExpression):
     24        (JSC::JSParser::parseAssignmentExpression):
     25        (JSC::JSParser::parseConditionalExpression):
     26        (JSC::JSParser::parseBinaryExpression):
     27        (JSC::JSParser::parseProperty):
     28        (JSC::JSParser::parseObjectLiteral):
     29        (JSC::JSParser::parseArrayLiteral):
     30        (JSC::JSParser::parseArguments):
     31        (JSC::JSParser::parseMemberExpression):
     32        * parser/Lexer.cpp:
     33        (JSC::Lexer::parseIdentifier):
     34        (JSC::Lexer::parseString):
     35        (JSC::Lexer::lex):
     36        * parser/Lexer.h:
     37        * parser/SyntaxChecker.h:
     38        (JSC::SyntaxChecker::createDotAccess):
     39        (JSC::SyntaxChecker::createProperty):
     40
    1412011-05-23  Michael Saboff  <msaboff@apple.com>
    242
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r78727 r87177  
    110110    static const bool NeedsFreeVariableInfo = true;
    111111    static const bool CanUseFunctionCache = true;
     112    static const int  DontBuildKeywords = 0;
     113    static const int  DontBuildStrings = 0;
    112114
    113115    ExpressionNode* makeBinaryNode(int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
     
    210212    }
    211213
    212     ExpressionNode* createDotAccess(ExpressionNode* base, const Identifier& property, int start, int divot, int end)
    213     {
    214         DotAccessorNode* node = new (m_globalData) DotAccessorNode(m_globalData, base, property);
     214    ExpressionNode* createDotAccess(ExpressionNode* base, const Identifier* property, int start, int divot, int end)
     215    {
     216        DotAccessorNode* node = new (m_globalData) DotAccessorNode(m_globalData, base, *property);
    215217        setExceptionLocation(node, start, divot, end);
    216218        return node;
  • trunk/Source/JavaScriptCore/parser/JSParser.cpp

    r85456 r87177  
    5050#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
    5151#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
     52#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) fail(); } while (0)
    5253#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
    5354#define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0)
     
    99100    };
    100101   
    101     void next(Lexer::LexType lexType = Lexer::IdentifyReservedWords)
     102    void next(unsigned lexType = 0)
    102103    {
    103104        m_lastLine = m_token.m_info.line;
     
    112113    }
    113114
    114     bool consume(JSTokenType expected)
     115    bool consume(JSTokenType expected, unsigned flags = 0)
    115116    {
    116117        bool result = m_token.m_type == expected;
    117118        failIfFalse(result);
    118         next();
     119        next(flags);
    119120        return result;
    120121    }
     
    797798            int varDivot = tokenStart() + 1;
    798799            initStart = tokenStart();
    799             next(); // consume '='
     800            next(TreeBuilder::DontBuildStrings); // consume '='
    800801            int initialAssignments = m_assignmentCount;
    801802            TreeExpression initializer = parseAssignmentExpression(context);
     
    829830        TreeExpression initializer = 0;
    830831        if (hasInitializer) {
    831             next(); // consume '='
     832            next(TreeBuilder::DontBuildStrings); // consume '='
    832833            initializer = parseAssignmentExpression(context);
    833834        }
     
    15531554    typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right);
    15541555    while (match(COMMA)) {
    1555         next();
     1556        next(TreeBuilder::DontBuildStrings);
    15561557        right = parseAssignmentExpression(context);
    15571558        failIfFalse(right);
     
    15981599        start = tokenStart();
    15991600        m_assignmentCount++;
    1600         next();
     1601        next(TreeBuilder::DontBuildStrings);
    16011602        if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
    16021603            failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier);
     
    16311632    m_nonTrivialExpressionCount++;
    16321633    m_nonLHSCount++;
    1633     next();
     1634    next(TreeBuilder::DontBuildStrings);
    16341635    TreeExpression lhs = parseAssignmentExpression(context);
    1635     consumeOrFail(COLON);
     1636    consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings);
    16361637
    16371638    TreeExpression rhs = parseAssignmentExpression(context);
     
    16711672        m_nonLHSCount++;
    16721673        int operatorToken = m_token.m_type;
    1673         next();
     1674        next(TreeBuilder::DontBuildStrings);
    16741675
    16751676        while (operatorStackDepth &&  context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
     
    17061707    case STRING: {
    17071708        const Identifier* ident = m_token.m_data.ident;
    1708         next(Lexer::IgnoreReservedWords);
     1709        if (complete || (wasIdent && (*ident == m_globalData->propertyNames->get || *ident == m_globalData->propertyNames->set)))
     1710            next(Lexer::IgnoreReservedWords);
     1711        else
     1712            next(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
     1713
    17091714        if (match(COLON)) {
    17101715            next();
     
    17481753{
    17491754    int startOffset = m_token.m_data.intValue;
    1750     consumeOrFail(OPENBRACE);
     1755    consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings);
    17511756
    17521757    if (match(CLOSEBRACE)) {
     
    17651770    TreePropertyList tail = propertyList;
    17661771    while (match(COMMA)) {
    1767         next();
     1772        next(TreeBuilder::DontBuildStrings);
    17681773        // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
    17691774        if (match(CLOSEBRACE))
     
    18301835template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
    18311836{
    1832     consumeOrFail(OPENBRACKET);
     1837    consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings);
    18331838
    18341839    int elisions = 0;
    18351840    while (match(COMMA)) {
    1836         next();
     1841        next(TreeBuilder::DontBuildStrings);
    18371842        elisions++;
    18381843    }
    18391844    if (match(CLOSEBRACKET)) {
    1840         next();
     1845        next(TreeBuilder::DontBuildStrings);
    18411846        return context.createArray(elisions);
    18421847    }
     
    18481853    elisions = 0;
    18491854    while (match(COMMA)) {
    1850         next();
     1855        next(TreeBuilder::DontBuildStrings);
    18511856        elisions = 0;
    18521857
     
    18571862
    18581863        if (match(CLOSEBRACKET)) {
    1859             next();
     1864            next(TreeBuilder::DontBuildStrings);
    18601865            return context.createArray(elisions, elementList);
    18611866        }
     
    19491954template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
    19501955{
    1951     consumeOrFail(OPENPAREN);
     1956    consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings);
    19521957    if (match(CLOSEPAREN)) {
    1953         next();
     1958        next(TreeBuilder::DontBuildStrings);
    19541959        return context.createArguments();
    19551960    }
     
    19601965    TreeArgumentsList tail = argList;
    19611966    while (match(COMMA)) {
    1962         next();
     1967        next(TreeBuilder::DontBuildStrings);
    19631968        TreeExpression arg = parseAssignmentExpression(context);
    19641969        failIfFalse(arg);
     
    20342039            m_nonTrivialExpressionCount++;
    20352040            int expressionEnd = lastTokenEnd();
    2036             next(Lexer::IgnoreReservedWords);
     2041            next(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
    20372042            matchOrFail(IDENT);
    2038             base = context.createDotAccess(base, *m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd());
     2043            base = context.createDotAccess(base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd());
    20392044            next();
    20402045            break;
  • trunk/Source/JavaScriptCore/parser/Lexer.cpp

    r75852 r87177  
    400400}
    401401
    402 ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* lvalp, LexType lexType)
     402template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* lvalp, unsigned lexType)
    403403{
    404404    bool bufferRequired = false;
     
    427427        if (UNLIKELY(m_buffer16.size() ? !isIdentPart(character) : !isIdentStart(character)))
    428428            return ERRORTOK;
    429         record16(character);
     429        if  (shouldCreateIdentifier)
     430            record16(character);
    430431        identifierStart = currentCharacter();
    431432    }
    432433
    433     if (!bufferRequired)
    434         identifierLength = currentCharacter() - identifierStart;
    435     else {
    436         if (identifierStart != currentCharacter())
    437             m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
    438         identifierStart = m_buffer16.data();
    439         identifierLength = m_buffer16.size();
    440     }
    441 
    442     const Identifier* ident = makeIdentifier(identifierStart, identifierLength);
    443     lvalp->ident = ident;
     434    const Identifier* ident = 0;
     435    if (shouldCreateIdentifier) {
     436        if (!bufferRequired)
     437            identifierLength = currentCharacter() - identifierStart;
     438        else {
     439            if (identifierStart != currentCharacter())
     440                m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
     441            identifierStart = m_buffer16.data();
     442            identifierLength = m_buffer16.size();
     443        }
     444
     445        ident = makeIdentifier(identifierStart, identifierLength);
     446        lvalp->ident = ident;
     447    } else
     448        lvalp->ident = 0;
     449
    444450    m_delimited = false;
    445451
    446     if (LIKELY(!bufferRequired && lexType == IdentifyReservedWords)) {
     452    if (LIKELY(!bufferRequired && !(lexType & IgnoreReservedWords))) {
     453        ASSERT(shouldCreateIdentifier);
    447454        // Keywords must not be recognized if there was an \uXXXX in the identifier.
    448455        const HashEntry* entry = m_keywordTable.entry(m_globalData, *ident);
     
    454461}
    455462
    456 ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp, bool strictMode)
     463template <bool shouldBuildStrings> ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp, bool strictMode)
    457464{
    458465    int stringQuoteCharacter = m_current;
     
    463470    while (m_current != stringQuoteCharacter) {
    464471        if (UNLIKELY(m_current == '\\')) {
    465             if (stringStart != currentCharacter())
     472            if (stringStart != currentCharacter() && shouldBuildStrings)
    466473                m_buffer16.append(stringStart, currentCharacter() - stringStart);
    467474            shift();
     
    471478            // Most common escape sequences first
    472479            if (escape) {
    473                 record16(escape);
     480                 if (shouldBuildStrings)
     481                     record16(escape);
    474482                shift();
    475483            } else if (UNLIKELY(isLineTerminator(m_current)))
     
    480488                    int prev = m_current;
    481489                    shift();
    482                     record16(convertHex(prev, m_current));
     490                    if (shouldBuildStrings)
     491                        record16(convertHex(prev, m_current));
    483492                    shift();
    484                 } else
     493                } else if (shouldBuildStrings)
    485494                    record16('x');
    486495            } else if (m_current == 'u') {
    487496                shift();
    488497                int character = getUnicodeCharacter();
    489                 if (character != -1)
    490                     record16(character);
    491                 else if (m_current == stringQuoteCharacter)
    492                     record16('u');
    493                 else // Only stringQuoteCharacter allowed after \u
     498                if (character != -1) {
     499                    if (shouldBuildStrings)
     500                        record16(character);
     501                } else if (m_current == stringQuoteCharacter) {
     502                    if (shouldBuildStrings)
     503                        record16('u');
     504                } else // Only stringQuoteCharacter allowed after \u
    494505                    return false;
    495506            } else if (strictMode && isASCIIDigit(m_current)) {
     
    499510                if (character1 != '0' || isASCIIDigit(m_current))
    500511                    return false;
    501                 record16(0);
     512                if (shouldBuildStrings)
     513                    record16(0);
    502514            } else if (!strictMode && isASCIIOctalDigit(m_current)) {
    503515                // Octal character sequences
     
    509521                    shift();
    510522                    if (character1 >= '0' && character1 <= '3' && isASCIIOctalDigit(m_current)) {
    511                         record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
     523                        if (shouldBuildStrings)
     524                            record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
    512525                        shift();
    513                     } else
    514                         record16((character1 - '0') * 8 + character2 - '0');
    515                 } else
    516                     record16(character1 - '0');
     526                    } else {
     527                        if (shouldBuildStrings)
     528                            record16((character1 - '0') * 8 + character2 - '0');
     529                    }
     530                } else {
     531                    if (shouldBuildStrings)
     532                        record16(character1 - '0');
     533                }
    517534            } else if (m_current != -1) {
    518                 record16(m_current);
     535                if (shouldBuildStrings)
     536                    record16(m_current);
    519537                shift();
    520538            } else
     
    536554    }
    537555
    538     if (currentCharacter() != stringStart)
     556    if (currentCharacter() != stringStart && shouldBuildStrings)
    539557        m_buffer16.append(stringStart, currentCharacter() - stringStart);
    540     lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
     558    if (shouldBuildStrings)
     559        lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
     560    else
     561        lvalp->ident = 0;
     562
    541563    m_buffer16.resize(0);
    542564    return true;
     
    713735}
    714736
    715 JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType lexType, bool strictMode)
     737JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, unsigned lexType, bool strictMode)
    716738{
    717739    ASSERT(!m_error);
     
    10261048        break;
    10271049    case CharacterQuote:
    1028         if (UNLIKELY(!parseString(lvalp, strictMode)))
    1029             goto returnError;
     1050        if (lexType & DontBuildStrings) {
     1051            if (UNLIKELY(!parseString<false>(lvalp, strictMode)))
     1052                goto returnError;
     1053        } else {
     1054            if (UNLIKELY(!parseString<true>(lvalp, strictMode)))
     1055                goto returnError;
     1056        }
    10301057        shift();
    10311058        m_delimited = false;
     
    10361063        // Fall through into CharacterBackSlash.
    10371064    case CharacterBackSlash:
    1038         token = parseIdentifier(lvalp, lexType);
     1065        if (lexType & DontBuildKeywords)
     1066            token = parseIdentifier<false>(lvalp, lexType);
     1067        else
     1068            token = parseIdentifier<true>(lvalp, lexType);
    10391069        break;
    10401070    case CharacterLineTerminator:
  • trunk/Source/JavaScriptCore/parser/Lexer.h

    r82696 r87177  
    5353
    5454        // Functions for the parser itself.
    55         enum LexType { IdentifyReservedWords, IgnoreReservedWords };
    56         JSTokenType lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType, bool strictMode);
     55        enum LexType {
     56            IgnoreReservedWords = 1,
     57            DontBuildStrings = 2,
     58            DontBuildKeywords = 4
     59        };
     60        JSTokenType lex(JSTokenData* lvalp, JSTokenInfo* llocp, unsigned, bool strictMode);
    5761        bool nextTokenIsColon();
    5862        int lineNumber() const { return m_lineNumber; }
     
    110114        ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
    111115
    112         ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, LexType);
    113         ALWAYS_INLINE bool parseString(JSTokenData* lvalp, bool strictMode);
     116        template <bool shouldBuildIdentifiers> ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, unsigned);
     117        template <bool shouldBuildStrings> ALWAYS_INLINE bool parseString(JSTokenData* lvalp, bool strictMode);
    114118        ALWAYS_INLINE void parseHex(double& returnValue);
    115119        ALWAYS_INLINE bool parseOctal(double& returnValue);
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r76177 r87177  
    2727#define SyntaxChecker_h
    2828
     29#include "Lexer.h"
    2930#include <yarr/YarrSyntaxChecker.h>
    3031
     
    114115    static const bool NeedsFreeVariableInfo = false;
    115116    static const bool CanUseFunctionCache = true;
     117    static const unsigned DontBuildKeywords = Lexer::DontBuildKeywords;
     118    static const unsigned DontBuildStrings = Lexer::DontBuildStrings;
    116119
    117120    int createSourceElements() { return 1; }
     
    140143    ExpressionType createNull() { return NullExpr; }
    141144    ExpressionType createBracketAccess(ExpressionType, ExpressionType, bool, int, int, int) { return BracketExpr; }
    142     ExpressionType createDotAccess(ExpressionType, const Identifier&, int, int, int) { return DotExpr; }
     145    ExpressionType createDotAccess(ExpressionType, const Identifier*, int, int, int) { return DotExpr; }
    143146    ExpressionType createRegExp(const Identifier& pattern, const Identifier&, int) { return Yarr::checkSyntax(pattern.ustring()) ? 0 : RegExpExpr; }
    144147    ExpressionType createNewExpr(ExpressionType, int, int, int, int) { return NewExpr; }
     
    154157    template <bool complete> Property createProperty(const Identifier* name, int, PropertyNode::Type type)
    155158    {
    156         ASSERT(name);
    157159        if (!complete)
    158160            return Property(type);
     161        ASSERT(name);
    159162        return Property(name, type);
    160163    }
Note: See TracChangeset for help on using the changeset viewer.