[JSC] Recover parser performance regression by async support
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 May 2016 20:57:20 +0000 (20:57 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 May 2016 20:57:20 +0000 (20:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158228

Reviewed by Saam Barati.

This patch recovers parser performance regression caused in r201481.

Compared to the version that reverts r201481, still ~1% regression remains.
But compared to ToT, this patch significantly improves the code-load performance.

In Linux x64 JSCOnly port, with GCC 5.3.1.

reverted v.s. patched.
                         reverted                  patched

closure              0.61805+-0.00376    ?     0.62280+-0.00525       ?
jquery               8.03778+-0.02114          8.03453+-0.04646

<geometric>          2.22883+-0.00836    ?     2.23688+-0.00995       ? might be 1.0036x slower

ToT v.s. patched.
                         baseline                  patched

closure              0.65490+-0.00351    ^     0.62473+-0.00363       ^ definitely 1.0483x faster
jquery               8.25373+-0.06256    ^     8.04701+-0.03455       ^ definitely 1.0257x faster

<geometric>          2.32488+-0.00921    ^     2.24210+-0.00592       ^ definitely 1.0369x faster

* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
* bytecode/UnlinkedFunctionExecutable.h:
Extend SourceParseMode.

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::isArrowFunctionParameters):
Do not call `matchSpecIdentifier()` as much as we can. This greatly improves the performance.

(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseStatement):
(JSC::Parser<LexerType>::parseFunctionParameters):
(JSC::Parser<LexerType>::parseFunctionInfo):
Do not touch `currentScope()->isGenerator()` even if it is unnecessary in parseFunctionInfo.
And accidental `syntaxChecker => context` changes are fixed.

(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseExpressionOrLabelStatement):
(JSC::Parser<LexerType>::parseImportClauseItem):
(JSC::Parser<LexerType>::parseExportDeclaration):
(JSC::Parser<LexerType>::parseAssignmentExpression):
Do not use matchSpecIdentifier() in the hot paths.

(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseMemberExpression):
(JSC::Parser<LexerType>::parseUnaryExpression):
(JSC::Parser<LexerType>::printUnexpectedTokenText): Deleted.
* parser/Parser.h:
(JSC::isIdentifierOrKeyword):
AWAIT shoud be one of the keywords. This AWAIT check is unnecessary.

(JSC::Parser::upperScope):
(JSC::Parser::matchSpecIdentifier):
Touching currentScope() and its member causes significant performance degradation.
We carefully remove the above access in the hot paths.

(JSC::Parser::isDisallowedIdentifierAwait):
* parser/ParserModes.h:
(JSC::SourceParseModeSet::SourceParseModeSet):
(JSC::SourceParseModeSet::contains):
(JSC::SourceParseModeSet::mergeSourceParseModes):
(JSC::isFunctionParseMode):
(JSC::isAsyncFunctionParseMode):
(JSC::isAsyncArrowFunctionParseMode):
(JSC::isAsyncFunctionWrapperParseMode):
(JSC::isAsyncFunctionBodyParseMode):
(JSC::isModuleParseMode):
(JSC::isProgramParseMode):
(JSC::constructAbilityForParseMode):
The parser frequently checks SourceParseMode. And variety of SourceParseMode becomes many.
So using switch onto SourceParseMode degrades the performance. Instead, we use bit tests to guard against
many SourceParseModes. We expect that this will be efficiently compiled into test & jmp.

* parser/ParserTokens.h:
Change AWAIT to one of the keywords, as the same to YIELD / LET.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201523 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/ParserModes.h
Source/JavaScriptCore/parser/ParserTokens.h

index b5dbb25..6df1f6d 100644 (file)
@@ -1,3 +1,91 @@
+2016-05-31  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Recover parser performance regression by async support
+        https://bugs.webkit.org/show_bug.cgi?id=158228
+
+        Reviewed by Saam Barati.
+
+        This patch recovers parser performance regression caused in r201481.
+
+        Compared to the version that reverts r201481, still ~1% regression remains.
+        But compared to ToT, this patch significantly improves the code-load performance.
+
+        In Linux x64 JSCOnly port, with GCC 5.3.1.
+
+        reverted v.s. patched.
+                                 reverted                  patched
+
+        closure              0.61805+-0.00376    ?     0.62280+-0.00525       ?
+        jquery               8.03778+-0.02114          8.03453+-0.04646
+
+        <geometric>          2.22883+-0.00836    ?     2.23688+-0.00995       ? might be 1.0036x slower
+
+        ToT v.s. patched.
+                                 baseline                  patched
+
+        closure              0.65490+-0.00351    ^     0.62473+-0.00363       ^ definitely 1.0483x faster
+        jquery               8.25373+-0.06256    ^     8.04701+-0.03455       ^ definitely 1.0257x faster
+
+        <geometric>          2.32488+-0.00921    ^     2.24210+-0.00592       ^ definitely 1.0369x faster
+
+        * bytecode/UnlinkedFunctionExecutable.cpp:
+        (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+        * bytecode/UnlinkedFunctionExecutable.h:
+        Extend SourceParseMode.
+
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseInner):
+        (JSC::Parser<LexerType>::isArrowFunctionParameters):
+        Do not call `matchSpecIdentifier()` as much as we can. This greatly improves the performance.
+
+        (JSC::Parser<LexerType>::parseStatementListItem):
+        (JSC::Parser<LexerType>::parseStatement):
+        (JSC::Parser<LexerType>::parseFunctionParameters):
+        (JSC::Parser<LexerType>::parseFunctionInfo):
+        Do not touch `currentScope()->isGenerator()` even if it is unnecessary in parseFunctionInfo.
+        And accidental `syntaxChecker => context` changes are fixed.
+
+        (JSC::Parser<LexerType>::parseClass):
+        (JSC::Parser<LexerType>::parseExpressionOrLabelStatement):
+        (JSC::Parser<LexerType>::parseImportClauseItem):
+        (JSC::Parser<LexerType>::parseExportDeclaration):
+        (JSC::Parser<LexerType>::parseAssignmentExpression):
+        Do not use matchSpecIdentifier() in the hot paths.
+
+        (JSC::Parser<LexerType>::parseProperty):
+        (JSC::Parser<LexerType>::parsePrimaryExpression):
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        (JSC::Parser<LexerType>::parseUnaryExpression):
+        (JSC::Parser<LexerType>::printUnexpectedTokenText): Deleted.
+        * parser/Parser.h:
+        (JSC::isIdentifierOrKeyword):
+        AWAIT shoud be one of the keywords. This AWAIT check is unnecessary.
+
+        (JSC::Parser::upperScope):
+        (JSC::Parser::matchSpecIdentifier):
+        Touching currentScope() and its member causes significant performance degradation.
+        We carefully remove the above access in the hot paths.
+
+        (JSC::Parser::isDisallowedIdentifierAwait):
+        * parser/ParserModes.h:
+        (JSC::SourceParseModeSet::SourceParseModeSet):
+        (JSC::SourceParseModeSet::contains):
+        (JSC::SourceParseModeSet::mergeSourceParseModes):
+        (JSC::isFunctionParseMode):
+        (JSC::isAsyncFunctionParseMode):
+        (JSC::isAsyncArrowFunctionParseMode):
+        (JSC::isAsyncFunctionWrapperParseMode):
+        (JSC::isAsyncFunctionBodyParseMode):
+        (JSC::isModuleParseMode):
+        (JSC::isProgramParseMode):
+        (JSC::constructAbilityForParseMode):
+        The parser frequently checks SourceParseMode. And variety of SourceParseMode becomes many.
+        So using switch onto SourceParseMode degrades the performance. Instead, we use bit tests to guard against
+        many SourceParseModes. We expect that this will be efficiently compiled into test & jmp.
+
+        * parser/ParserTokens.h:
+        Change AWAIT to one of the keywords, as the same to YIELD / LET.
+
 2016-05-31  Saam Barati  <sbarati@apple.com>
 
         Web Inspector: capturing with Allocations timeline causes GC to take 100x longer and cause frame drops
index 7b60fed..81d34f7 100644 (file)
@@ -91,6 +91,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_typeProfilingEndOffset(node->startStartOffset() + node->source().length() - 1)
     , m_parameterCount(node->parameterCount())
     , m_features(0)
+    , m_sourceParseMode(node->parseMode())
     , m_isInStrictContext(node->isInStrictContext())
     , m_hasCapturedVariables(false)
     , m_isBuiltinFunction(kind == UnlinkedBuiltinFunction)
@@ -99,7 +100,6 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_functionMode(static_cast<unsigned>(node->functionMode()))
     , m_superBinding(static_cast<unsigned>(node->superBinding()))
     , m_derivedContextType(static_cast<unsigned>(derivedContextType))
-    , m_sourceParseMode(static_cast<unsigned>(node->parseMode()))
     , m_name(node->ident())
     , m_ecmaName(node->ecmaName())
     , m_inferredName(node->inferredName())
@@ -112,7 +112,6 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     ASSERT(m_functionMode == static_cast<unsigned>(node->functionMode()));
     ASSERT(m_superBinding == static_cast<unsigned>(node->superBinding()));
     ASSERT(m_derivedContextType == static_cast<unsigned>(derivedContextType));
-    ASSERT(m_sourceParseMode == static_cast<unsigned>(node->parseMode()));
 
     m_parentScopeTDZVariables.swap(parentScopeTDZVariables);
 }
index 6c04329..e158d33 100644 (file)
@@ -158,6 +158,7 @@ private:
     unsigned m_typeProfilingEndOffset;
     unsigned m_parameterCount;
     CodeFeatures m_features;
+    SourceParseMode m_sourceParseMode;
     unsigned m_isInStrictContext : 1;
     unsigned m_hasCapturedVariables : 1;
     unsigned m_isBuiltinFunction : 1;
@@ -166,7 +167,6 @@ private:
     unsigned m_functionMode : 2; // FunctionMode
     unsigned m_superBinding : 1;
     unsigned m_derivedContextType: 2;
-    unsigned m_sourceParseMode : 4; // SourceParseMode
 
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
index a12bcdc..381886e 100644 (file)
@@ -80,8 +80,6 @@
         semanticFail("Cannot use the reserved word '", getToken(), "' as a ", __VA_ARGS__); \
     if (m_token.m_type & KeywordTokenFlag) \
         semanticFail("Cannot use the keyword '", getToken(), "' as a ", __VA_ARGS__); \
-    if (isDisallowedIdentifierAwait(m_token)) \
-        semanticFail("Can't use 'await' as a ", __VA_ARGS__, " ", disallowedIdentifierAwaitReason()); \
 } while (0)
 
 using namespace std;
@@ -258,12 +256,12 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     bool isArrowFunctionBodyExpression = parseMode == SourceParseMode::AsyncArrowFunctionBodyMode && !match(OPENBRACE);
     if (m_lexer->isReparsingFunction()) {
         ParserFunctionInfo<ASTBuilder> functionInfo;
-        if (parseMode == SourceParseMode::GeneratorBodyMode || isAsyncFunctionBodyParseMode(parseMode))
+        if (SourceParseModeSet(SourceParseMode::GeneratorBodyMode).contains(parseMode) || isAsyncFunctionBodyParseMode(parseMode))
             m_parameters = createGeneratorParameters(context);
         else
             m_parameters = parseFunctionParameters(context, parseMode, functionInfo);
 
-        if ((parseMode == SourceParseMode::ArrowFunctionMode || parseMode == SourceParseMode::AsyncArrowFunctionMode) && !hasError()) {
+        if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(parseMode) && !hasError()) {
             // The only way we could have an error wile reparsing is if we run out of stack space.
             RELEASE_ASSERT(match(ARROWFUNCTION));
             next();
@@ -309,7 +307,7 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     for (auto& entry : capturedVariables)
         varDeclarations.markVariableAsCaptured(entry);
 
-    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(parseMode)) {
+    if (SourceParseModeSet(SourceParseMode::GeneratorWrapperFunctionMode).contains(parseMode) || isAsyncFunctionWrapperParseMode(parseMode)) {
         if (scope->usedVariablesContains(m_vm->propertyNames->arguments.impl()))
             context.propagateArgumentsUse();
     }
@@ -354,21 +352,10 @@ void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, Declara
 template <typename LexerType>
 bool Parser<LexerType>::isArrowFunctionParameters()
 {
-    bool isOpenParen = match(OPENPAREN);
-    bool isIdent = matchSpecIdentifier();
-    
-    if (!isOpenParen && !isIdent)
-        return false;
-
-    bool isArrowFunction = false;
-    SavePoint saveArrowFunctionPoint = createSavePoint();
-        
-    if (isIdent) {
-        next();
-        isArrowFunction = match(ARROWFUNCTION);
-    } else {
-        RELEASE_ASSERT(isOpenParen);
+    if (match(OPENPAREN)) {
+        SavePoint saveArrowFunctionPoint = createSavePoint();
         next();
+        bool isArrowFunction = false;
         if (match(CLOSEPAREN)) {
             next();
             isArrowFunction = match(ARROWFUNCTION);
@@ -380,14 +367,22 @@ bool Parser<LexerType>::isArrowFunctionParameters()
 
             unsigned parametersCount = 0;
             isArrowFunction = parseFormalParameters(syntaxChecker, syntaxChecker.createFormalParameterList(), parametersCount) && consume(CLOSEPAREN) && match(ARROWFUNCTION);
-                
+
             popScope(fakeScope, syntaxChecker.NeedsFreeVariableInfo);
         }
+        restoreSavePoint(saveArrowFunctionPoint);
+        return isArrowFunction;
     }
-        
-    restoreSavePoint(saveArrowFunctionPoint);
-        
-    return isArrowFunction;
+
+    if (matchSpecIdentifier()) {
+        SavePoint saveArrowFunctionPoint = createSavePoint();
+        next();
+        bool isArrowFunction = match(ARROWFUNCTION);
+        restoreSavePoint(saveArrowFunctionPoint);
+        return isArrowFunction;
+    }
+
+    return false;
 }
 
 template <typename LexerType>
@@ -600,7 +595,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
             // For example, under a generator context, matchSpecIdentifier() for "yield" returns `false`.
             // But we would like to enter parseVariableDeclaration and raise an error under the context of parseVariableDeclaration
             // to raise consistent errors between "var", "const" and "let".
-            if (!(match(IDENT) || match(AWAIT) || match(LET) || match(YIELD)) && !match(OPENBRACE) && !match(OPENBRACKET))
+            if (!(match(IDENT) || match(LET) || match(YIELD) || match(AWAIT)) && !match(OPENBRACE) && !match(OPENBRACKET))
                 shouldParseVariableDeclaration = false;
             restoreSavePoint(savePoint);
         }
@@ -619,18 +614,21 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
     case FUNCTION:
         result = parseFunctionDeclaration(context);
         break;
-
     case IDENT:
-        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
-            // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
-            // but could be mistakenly parsed as an AsyncFunctionExpression.
-            SavePoint savePoint = createSavePoint();
-            next();
-            if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) {
-                result = parseAsyncFunctionDeclaration(context);
-                break;
+        // FIXME: This branch contributes to a 1% octane code-load regression.
+        // https://bugs.webkit.org/show_bug.cgi?id=158211
+        if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async)) {
+            if (m_runtimeFlags.isAsyncAwaitEnabled()) {
+                // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
+                // but could be mistakenly parsed as an AsyncFunctionExpression.
+                SavePoint savePoint = createSavePoint();
+                next();
+                if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) {
+                    result = parseAsyncFunctionDeclaration(context);
+                    break;
+                }
+                restoreSavePoint(savePoint);
             }
-            restoreSavePoint(savePoint);
         }
         FALLTHROUGH;
     case AWAIT:
@@ -1735,17 +1733,20 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(Tre
     case DEFAULT:
         // These tokens imply the end of a set of source elements
         return 0;
-
     case IDENT:
-        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
-            SavePoint savePoint = createSavePoint();
-            next();
-            if (match(FUNCTION) && !m_lexer->prevTerminator()) {
-                const bool isAsync = true;
-                result = parseFunctionDeclarationStatement(context, isAsync, parentAllowsFunctionDeclarationAsStatement);
-                break;
+        // FIXME: This branch contributes to a 1% octane code-load regression.
+        // https://bugs.webkit.org/show_bug.cgi?id=158211
+        if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async)) {
+            if (m_runtimeFlags.isAsyncAwaitEnabled()) {
+                SavePoint savePoint = createSavePoint();
+                next();
+                if (match(FUNCTION) && !m_lexer->prevTerminator()) {
+                    const bool isAsync = true;
+                    result = parseFunctionDeclarationStatement(context, isAsync, parentAllowsFunctionDeclarationAsStatement);
+                    break;
+                }
+                restoreSavePoint(savePoint);
             }
-            restoreSavePoint(savePoint);
         }
         FALLTHROUGH;
     case AWAIT:
@@ -1929,11 +1930,11 @@ static const char* stringForFunctionMode(SourceParseMode mode)
 
 template <typename LexerType> template <class TreeBuilder, class FunctionInfoType> typename TreeBuilder::FormalParameterList Parser<LexerType>::parseFunctionParameters(TreeBuilder& context, SourceParseMode mode, FunctionInfoType& functionInfo)
 {
-    RELEASE_ASSERT(mode != SourceParseMode::ProgramMode && mode != SourceParseMode::ModuleAnalyzeMode && mode != SourceParseMode::ModuleEvaluateMode);
+    ASSERT(!(SourceParseModeSet(SourceParseMode::ProgramMode, SourceParseMode::ModuleAnalyzeMode, SourceParseMode::ModuleEvaluateMode).contains(mode)));
     TreeFormalParameterList parameterList = context.createFormalParameterList();
     SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Parameters);
     
-    if (mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode) {
+    if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(mode)) {
         if (!matchSpecIdentifier() && !match(OPENPAREN)) {
             semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
             failWithMessage("Expected an arrow function input parameter");
@@ -2025,9 +2026,9 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
 {
     RELEASE_ASSERT(isFunctionParseMode(mode));
 
-    bool upperScopeIsGenerator = currentScope()->isGenerator();
     bool isDisallowedAwaitFunctionName = isDisallowedIdentifierAwait(m_token);
     const char* isDisallowedAwaitFunctionNameReason = isDisallowedAwaitFunctionName ? disallowedIdentifierAwaitReason() : nullptr;
+
     AutoPopScopeRef functionScope(this, pushScope());
     functionScope->setSourceParseMode(mode);
     SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Body);
@@ -2066,7 +2067,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             ASSERT(endLocation.startOffset >= endLocation.lineStartOffset);
             
             FunctionBodyType functionBodyType;
-            if (mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode)
+            if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(mode))
                 functionBodyType = cachedInfo->isBodyArrowExpression ?  ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
             else
                 functionBodyType = StandardFunctionBodyBlock;
@@ -2109,7 +2110,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
 
     SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
 
-    if (mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode) {
+    if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(mode)) {
         startLocation = tokenLocation();
         functionInfo.startLine = tokenLine();
         startColumn = tokenColumn();
@@ -2121,7 +2122,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             return true;
         {
             SetForScope<bool> overrideAllowAwait(m_parserState.allowAwait, !isAsyncFunctionParseMode(mode));
-            parseFunctionParameters(context, mode, functionInfo);
+            parseFunctionParameters(syntaxChecker, mode, functionInfo);
         }
 
         propagateError();
@@ -2154,8 +2155,9 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         //     function * BindingIdentifier[Yield]opt ( FormalParameters[Yield] ) { GeneratorBody }
         //
         // The name of FunctionExpression and AsyncFunctionExpression can accept "yield" even in the context of generator.
-        if (functionDefinitionType == FunctionDefinitionType::Expression && (mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::AsyncFunctionMode))
-            upperScopeIsGenerator = false;
+        bool upperScopeIsGenerator = false;
+        if (!(functionDefinitionType == FunctionDefinitionType::Expression && SourceParseModeSet(SourceParseMode::NormalFunctionMode, SourceParseMode::AsyncFunctionMode).contains(mode)))
+            upperScopeIsGenerator = upperScope(1)->isGenerator();
 
         if (matchSpecIdentifier(upperScopeIsGenerator)) {
             bool allowsAwait = functionDefinitionType == FunctionDefinitionType::Declaration || mode != SourceParseMode::AsyncFunctionMode;
@@ -2170,8 +2172,10 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             if (!nameIsInContainingScope)
                 failIfTrueIfStrict(functionScope->declareCallee(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
         } else if (requirements == FunctionNeedsName) {
-            semanticFailIfTrue(match(OPENPAREN) && mode == SourceParseMode::NormalFunctionMode, "Function statements must have a name");
-            semanticFailIfTrue(match(OPENPAREN) && mode == SourceParseMode::AsyncFunctionMode, "Async function statements must have a name");
+            if (match(OPENPAREN)) {
+                semanticFailIfTrue(mode == SourceParseMode::NormalFunctionMode, "Function statements must have a name");
+                semanticFailIfTrue(mode == SourceParseMode::AsyncFunctionMode, "Async function statements must have a name");
+            }
             semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
             failDueToUnexpectedToken();
             return false;
@@ -2189,7 +2193,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             return true;
         {
             SetForScope<bool> overrideAllowAwait(m_parserState.allowAwait, !isAsyncFunctionParseMode(mode));
-            parseFunctionParameters(context, mode, functionInfo);
+            parseFunctionParameters(syntaxChecker, mode, functionInfo);
             propagateError();
         }
         
@@ -2235,7 +2239,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         return parseFunctionBody(context, syntaxChecker, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, mode);
     };
 
-    if (mode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(mode)) {
+    if (UNLIKELY((SourceParseModeSet(SourceParseMode::GeneratorWrapperFunctionMode).contains(mode)) || isAsyncFunctionWrapperParseMode(mode))) {
         AutoPopScopeRef generatorBodyScope(this, pushScope());
         SourceParseMode innerParseMode = SourceParseMode::GeneratorBodyMode;
         if (isAsyncFunctionWrapperParseMode(mode)) {
@@ -2261,7 +2265,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     failIfFalse(functionInfo.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
     context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
     if (functionScope->strictMode() && functionInfo.name) {
-        RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(mode));
+        RELEASE_ASSERT((SourceParseModeSet(SourceParseMode::NormalFunctionMode, SourceParseMode::MethodMode, SourceParseMode::ArrowFunctionMode, SourceParseMode::GeneratorBodyMode, SourceParseMode::GeneratorWrapperFunctionMode).contains(mode)) || isAsyncFunctionWrapperParseMode(mode));
         semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
         semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
     }
@@ -2475,7 +2479,6 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
         bool isSetter = false;
         bool isGenerator = false;
         bool isAsyncMethod = false;
-
         if (consume(TIMES))
             isGenerator = true;
 
@@ -2487,17 +2490,19 @@ parseMethod:
             ASSERT(ident);
             next();
             break;
-        case AWAIT:
         case IDENT:
+        case AWAIT:
             ident = m_token.m_data.ident;
             ASSERT(ident);
             next();
             if (!isGenerator && !isAsyncMethod && (matchIdentifierOrKeyword() || match(STRING) || match(DOUBLE) || match(INTEGER) || match(OPENBRACKET))) {
                 isGetter = *ident == propertyNames.get;
                 isSetter = *ident == propertyNames.set;
-                if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && !isAsyncMethod && *ident == propertyNames.async && !m_lexer->prevTerminator())) {
-                    isAsyncMethod = true;
-                    goto parseMethod;
+                if (UNLIKELY(!isAsyncMethod && *ident == propertyNames.async && !m_lexer->prevTerminator())) {
+                    if (m_runtimeFlags.isAsyncAwaitEnabled()) {
+                        isAsyncMethod = true;
+                        goto parseMethod;
+                    }
                 }
             }
             break;
@@ -2618,12 +2623,14 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionOrL
                 failDueToUnexpectedToken();
             return context.createExprStatement(location, expression, start, m_lastTokenEndPosition.line);
         }
+        // FIXME: This branch contributes to a 1% octane code-load regression.
+        // https://bugs.webkit.org/show_bug.cgi?id=158211
+        if (UNLIKELY(match(AWAIT)))
+            semanticFailIfTrue(isDisallowedIdentifierAwait(m_token), "Can't use 'await' as a label ", disallowedIdentifierAwaitReason());
         const Identifier* ident = m_token.m_data.ident;
-        const bool isDisallowedLabelAwait = isDisallowedIdentifierAwait(m_token);
         JSTextPosition end = tokenEndPosition();
         next();
         consumeOrFail(COLON, "Labels must be followed by a ':'");
-        semanticFailIfTrue(isDisallowedLabelAwait, "Can't use 'await' as a label ", disallowedIdentifierAwaitReason());
         if (!m_syntaxAlreadyValidated) {
             // This is O(N^2) over the current list of consecutive labels, but I
             // have never seen more than one label in a row in the real world.
@@ -2858,8 +2865,8 @@ template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerT
     }
     }
 
-    semanticFailIfTrue(localNameToken.m_type & KeywordTokenFlag, "Cannot use keyword as imported binding name");
     semanticFailIfTrue(localNameToken.m_type == AWAIT, "Cannot use 'await' as an imported binding name");
+    semanticFailIfTrue(localNameToken.m_type & KeywordTokenFlag, "Cannot use keyword as imported binding name");
     DeclarationResultMask declarationResult = declareVariable(localName, DeclarationType::ConstDeclaration, (specifierType == ImportSpecifierType::NamespaceImport) ? DeclarationImportType::ImportedNamespace : DeclarationImportType::Imported);
     if (declarationResult != DeclarationResult::Valid) {
         failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare an imported binding named ", localName->impl(), " in strict mode");
@@ -3002,12 +3009,14 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclara
         bool isAsyncFunctionExport = false;
         SavePoint savePoint = createSavePoint();
 
-        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
-            next();
-            if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator()))
-                isAsyncFunctionExport = true;
-            else
-                restoreSavePoint(savePoint);
+        if (UNLIKELY(matchContextualKeyword(m_vm->propertyNames->async))) {
+            if (m_runtimeFlags.isAsyncAwaitEnabled()) {
+                next();
+                if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator()))
+                    isAsyncFunctionExport = true;
+                else
+                    restoreSavePoint(savePoint);
+            }
         }
 
         bool startsWithFunction = match(FUNCTION);
@@ -3153,12 +3162,15 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclara
             break;
 
         default:
-            if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
-                next();
-                semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator");
-                result = parseAsyncFunctionDeclaration(context, ExportType::Exported);
-                break;
+            if (UNLIKELY(matchContextualKeyword(m_vm->propertyNames->async))) {
+                if (m_runtimeFlags.isAsyncAwaitEnabled()) {
+                    next();
+                    semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator");
+                    result = parseAsyncFunctionDeclaration(context, ExportType::Exported);
+                    break;
+                }
             }
+
             failWithMessage("Expected either a declaration or a variable statement");
             break;
         }
@@ -3223,26 +3235,33 @@ template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmen
     ASSERT(!hasError());
     
     failIfStackOverflow();
+
+    if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator()))
+        return parseYieldExpression(context);
+
     JSTextPosition start = tokenStartPosition();
     JSTokenLocation location(tokenLocation());
     int initialAssignmentCount = m_parserState.assignmentCount;
     int initialNonLHSCount = m_parserState.nonLHSCount;
     bool maybeAssignmentPattern = match(OPENBRACE) || match(OPENBRACKET);
     bool wasOpenParen = match(OPENPAREN);
-    bool isValidArrowFunctionStart = match(OPENPAREN) || matchSpecIdentifier();
+    // Do not use matchSpecIdentifier() here since it is slower than isIdentifierOrKeyword.
+    // Whether spec identifier is will be validated by isArrowFunctionParameters().
+    bool wasIdentifierOrKeyword = isIdentifierOrKeyword(m_token);
+    bool maybeValidArrowFunctionStart = wasOpenParen || wasIdentifierOrKeyword;
     SavePoint savePoint = createSavePoint();
     size_t usedVariablesSize = 0;
-    if (wasOpenParen || UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
+
+    // FIXME: This branch contributes to a 1% octane code-load regression.
+    // https://bugs.webkit.org/show_bug.cgi?id=158211
+    if (wasOpenParen || (wasIdentifierOrKeyword && m_runtimeFlags.isAsyncAwaitEnabled() && UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async))) {
         usedVariablesSize = currentScope()->currentUsedVariablesSize();
         currentScope()->pushUsedVariableSet();
     }
 
-    if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator()))
-        return parseYieldExpression(context);
-
     TreeExpression lhs = parseConditionalExpression(context);
 
-    if (isValidArrowFunctionStart && !match(EOFTOK)) {
+    if (maybeValidArrowFunctionStart && !match(EOFTOK)) {
         bool isArrowFunctionToken = match(ARROWFUNCTION);
         if (!lhs || isArrowFunctionToken) {
             SavePointWithError errorRestorationSavePoint = createSavePointForError();
@@ -3483,15 +3502,14 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeB
     bool isGenerator = false;
     bool isClassProperty = false;
     bool isAsyncMethod = false;
-
     if (consume(TIMES))
         isGenerator = true;
 
 parseProperty:
     switch (m_token.m_type) {
     namedProperty:
-    case AWAIT:
     case IDENT:
+    case AWAIT:
         wasIdent = true;
         FALLTHROUGH;
     case STRING: {
@@ -3542,8 +3560,7 @@ parseProperty:
             isAsyncMethod = true;
             failIfTrue(m_lexer->prevTerminator(), "Expected a property name following keyword 'async'");
             goto parseProperty;
-        }
-        else
+        } else
             failWithMessage("Expected a ':' following the property name '", ident->impl(), "'");
         return parseGetterSetter(context, complete, type, getterOrSetterStartOffset, ConstructorKind::None, isClassProperty);
     }
@@ -3965,8 +3982,12 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpre
         const Identifier* ident = m_token.m_data.ident;
         JSTokenLocation location(tokenLocation());
         next();
-        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && match(FUNCTION) && !m_lexer->prevTerminator() && *ident == m_vm->propertyNames->async))
-            return parseAsyncFunctionExpression(context);
+        // FIXME: This branch contributes to a 1% octane code-load regression.
+        // https://bugs.webkit.org/show_bug.cgi?id=158211
+        if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator() && *ident == m_vm->propertyNames->async)) {
+            if (m_runtimeFlags.isAsyncAwaitEnabled())
+                return parseAsyncFunctionExpression(context);
+        }
         currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident);
         m_parserState.lastIdentifier = ident;
         return context.createResolve(location, *ident, start, lastTokenEndPosition());
@@ -4161,7 +4182,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
             }
         }
     } else if (!baseIsNewTarget) {
-        currentFunctionScope()->setNeedsSuperBinding();
+        // FIXME: This branch contributes to a 1% octane code-load regression.
+        // https://bugs.webkit.org/show_bug.cgi?id=158211
         const bool isAsync = matchContextualKeyword(m_vm->propertyNames->async);
         base = parsePrimaryExpression(context);
         failIfFalse(base, "Cannot parse base expression");
@@ -4256,7 +4278,6 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
             m_parserState.nonLHSCount = nonLHSCount;
             break;
         }
-
         default:
             goto endMemberExpression;
         }
@@ -4325,8 +4346,12 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpress
     bool requiresLExpr = false;
     unsigned lastOperator = 0;
 
-    if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && match(AWAIT) && currentFunctionScope()->isAsyncFunction()))
-        return parseAwaitExpression(context);
+    // FIXME: This branch contributes to a 1% octane code-load regression.
+    // https://bugs.webkit.org/show_bug.cgi?id=158211
+    if (UNLIKELY(match(AWAIT))) {
+        if (m_runtimeFlags.isAsyncAwaitEnabled() && currentFunctionScope()->isAsyncFunction())
+            return parseAwaitExpression(context);
+    }
 
     while (isUnaryOp(m_token.m_type)) {
         if (strictMode()) {
@@ -4509,7 +4534,6 @@ template <typename LexerType> void Parser<LexerType>::printUnexpectedTokenText(W
         out.print("Invalid private name '", getToken(), "'");
         return;
 
-    case AWAIT:
     case IDENT:
         out.print("Unexpected identifier '", getToken(), "'");
         return;
index ab6f11d..f955710 100644 (file)
@@ -126,7 +126,7 @@ ALWAYS_INLINE static bool isEvalOrArgumentsIdentifier(const VM* vm, const Identi
 }
 ALWAYS_INLINE static bool isIdentifierOrKeyword(const JSToken& token)
 {
-    return token.m_type == IDENT || token.m_type == AWAIT || token.m_type & KeywordTokenFlag;
+    return token.m_type == IDENT || token.m_type & KeywordTokenFlag;
 }
 
 class ModuleScopeData : public RefCounted<ModuleScopeData> {
@@ -1072,6 +1072,12 @@ private:
 
     ALWAYS_INLINE bool isEvalOrArguments(const Identifier* ident) { return isEvalOrArgumentsIdentifier(m_vm, ident); }
 
+    ScopeRef upperScope(unsigned n)
+    {
+        ASSERT(m_scopeStack.size() >= (1 + n));
+        return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1 - n);
+    }
+
     ScopeRef currentScope()
     {
         return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
@@ -1445,12 +1451,13 @@ private:
     // http://ecma-international.org/ecma-262/6.0/#sec-generator-function-definitions-static-semantics-early-errors
     ALWAYS_INLINE bool matchSpecIdentifier(bool inGenerator)
     {
-        return match(IDENT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(inGenerator) || match(AWAIT);
+        return match(IDENT) || match(AWAIT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(inGenerator);
     }
 
+    // http://ecma-international.org/ecma-262/6.0/#sec-generator-function-definitions-static-semantics-early-errors
     ALWAYS_INLINE bool matchSpecIdentifier()
     {
-        return matchSpecIdentifier(currentScope()->isGenerator());
+        return match(IDENT) || match(AWAIT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(currentScope()->isGenerator());
     }
 
     template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
@@ -1567,7 +1574,7 @@ private:
 
     bool isDisallowedIdentifierAwait(const JSToken& token)
     {
-        return token.m_type == AWAIT && (currentScope()->isAsyncFunctionBoundary() || currentScope()->isModule() || !m_parserState.allowAwait);
+        return token.m_type == AWAIT && (!m_parserState.allowAwait || currentScope()->isAsyncFunctionBoundary() || currentScope()->isModule());
     }
 
     const char* disallowedIdentifierAwaitReason()
index 06c5389..7ab241d 100644 (file)
@@ -43,233 +43,120 @@ enum DebuggerMode { DebuggerOff, DebuggerOn };
 
 enum class FunctionMode { FunctionExpression, FunctionDeclaration, MethodDefinition };
 
-enum class SourceParseMode : uint8_t {
-    NormalFunctionMode,
-    GeneratorBodyMode,
-    GeneratorWrapperFunctionMode,
-    GetterMode,
-    SetterMode,
-    MethodMode,
-    ArrowFunctionMode,
-    AsyncFunctionBodyMode,
-    AsyncArrowFunctionBodyMode,
-    AsyncFunctionMode,
-    AsyncMethodMode,
-    AsyncArrowFunctionMode,
-    ProgramMode,
-    ModuleAnalyzeMode,
-    ModuleEvaluateMode
+// When you add a new source parse mode, do not forget to ensure that the predicates defined in this
+// file work with the newly added mode.
+enum class SourceParseMode : uint16_t {
+    NormalFunctionMode            = 0b0000000000000001,
+    GeneratorBodyMode             = 0b0000000000000010,
+    GeneratorWrapperFunctionMode  = 0b0000000000000100,
+    GetterMode                    = 0b0000000000001000,
+    SetterMode                    = 0b0000000000010000,
+    MethodMode                    = 0b0000000000100000,
+    ArrowFunctionMode             = 0b0000000001000000,
+    AsyncFunctionBodyMode         = 0b0000000010000000,
+    AsyncArrowFunctionBodyMode    = 0b0000000100000000,
+    AsyncFunctionMode             = 0b0000001000000000,
+    AsyncMethodMode               = 0b0000010000000000,
+    AsyncArrowFunctionMode        = 0b0000100000000000,
+    ProgramMode                   = 0b0001000000000000,
+    ModuleAnalyzeMode             = 0b0010000000000000,
+    ModuleEvaluateMode            = 0b0100000000000000,
 };
 
-inline bool isFunctionParseMode(SourceParseMode parseMode)
-{
-    switch (parseMode) {
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-        return true;
-
-    case SourceParseMode::ProgramMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-        return false;
+class SourceParseModeSet {
+public:
+    template<typename... Modes>
+    SourceParseModeSet(Modes... args)
+        : m_mask(mergeSourceParseModes(args...))
+    {
     }
-    RELEASE_ASSERT_NOT_REACHED();
-    return false;
-}
 
-inline bool isAsyncFunctionParseMode(SourceParseMode parseMode)
-{
-    switch (parseMode) {
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-        return true;
-
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-    case SourceParseMode::ProgramMode:
-        return false;
+    ALWAYS_INLINE bool contains(SourceParseMode mode)
+    {
+        return static_cast<unsigned>(mode) & m_mask;
+    }
+
+private:
+    ALWAYS_INLINE static unsigned mergeSourceParseModes(SourceParseMode mode)
+    {
+        return static_cast<unsigned>(mode);
     }
-    RELEASE_ASSERT_NOT_REACHED();
-    return false;
+
+    template<typename... Rest>
+    ALWAYS_INLINE static unsigned mergeSourceParseModes(SourceParseMode mode, Rest... rest)
+    {
+        return static_cast<unsigned>(mode) | mergeSourceParseModes(rest...);
+    }
+
+    const unsigned m_mask;
+};
+
+ALWAYS_INLINE bool isFunctionParseMode(SourceParseMode parseMode)
+{
+    return SourceParseModeSet(
+        SourceParseMode::NormalFunctionMode,
+        SourceParseMode::GeneratorBodyMode,
+        SourceParseMode::GeneratorWrapperFunctionMode,
+        SourceParseMode::GetterMode,
+        SourceParseMode::SetterMode,
+        SourceParseMode::MethodMode,
+        SourceParseMode::ArrowFunctionMode,
+        SourceParseMode::AsyncFunctionBodyMode,
+        SourceParseMode::AsyncFunctionMode,
+        SourceParseMode::AsyncMethodMode,
+        SourceParseMode::AsyncArrowFunctionMode,
+        SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
 }
 
-inline bool isAsyncArrowFunctionParseMode(SourceParseMode parseMode)
+ALWAYS_INLINE bool isAsyncFunctionParseMode(SourceParseMode parseMode)
 {
-    switch (parseMode) {
-    case SourceParseMode::AsyncArrowFunctionMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-        return true;
-
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::ProgramMode:
-        return false;
-    }
+    return SourceParseModeSet(
+        SourceParseMode::AsyncFunctionBodyMode,
+        SourceParseMode::AsyncFunctionMode,
+        SourceParseMode::AsyncMethodMode,
+        SourceParseMode::AsyncArrowFunctionMode,
+        SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
+}
 
-    RELEASE_ASSERT_NOT_REACHED();
-    return false;
+ALWAYS_INLINE bool isAsyncArrowFunctionParseMode(SourceParseMode parseMode)
+{
+    return SourceParseModeSet(
+        SourceParseMode::AsyncArrowFunctionMode,
+        SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
 }
 
-inline bool isAsyncFunctionWrapperParseMode(SourceParseMode parseMode)
+ALWAYS_INLINE bool isAsyncFunctionWrapperParseMode(SourceParseMode parseMode)
 {
-    switch (parseMode) {
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-        return true;
-
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-    case SourceParseMode::ProgramMode:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return false;
+    return SourceParseModeSet(
+        SourceParseMode::AsyncArrowFunctionMode,
+        SourceParseMode::AsyncFunctionMode,
+        SourceParseMode::AsyncMethodMode).contains(parseMode);
 }
 
-inline bool isAsyncFunctionBodyParseMode(SourceParseMode parseMode)
+ALWAYS_INLINE bool isAsyncFunctionBodyParseMode(SourceParseMode parseMode)
 {
-    switch (parseMode) {
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-        return true;
-
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-    case SourceParseMode::ProgramMode:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return false;
+    return SourceParseModeSet(
+        SourceParseMode::AsyncFunctionBodyMode,
+        SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
 }
 
-inline bool isModuleParseMode(SourceParseMode parseMode)
+ALWAYS_INLINE bool isModuleParseMode(SourceParseMode parseMode)
 {
-    switch (parseMode) {
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-        return true;
-
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-    case SourceParseMode::ProgramMode:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return false;
+    return SourceParseModeSet(
+        SourceParseMode::ModuleAnalyzeMode,
+        SourceParseMode::ModuleEvaluateMode).contains(parseMode);
 }
 
-inline bool isProgramParseMode(SourceParseMode parseMode)
+ALWAYS_INLINE bool isProgramParseMode(SourceParseMode parseMode)
 {
-    switch (parseMode) {
-    case SourceParseMode::ProgramMode:
-        return true;
-
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-        return false;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return false;
+    return SourceParseModeSet(SourceParseMode::ProgramMode).contains(parseMode);
 }
 
-inline ConstructAbility constructAbilityForParseMode(SourceParseMode parseMode)
+ALWAYS_INLINE ConstructAbility constructAbilityForParseMode(SourceParseMode parseMode)
 {
-    switch (parseMode) {
-    case SourceParseMode::NormalFunctionMode:
+    if (parseMode == SourceParseMode::NormalFunctionMode)
         return ConstructAbility::CanConstruct;
-
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-        return ConstructAbility::CannotConstruct;
-
-    case SourceParseMode::ProgramMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-        break;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return ConstructAbility::CanConstruct;
+    return ConstructAbility::CannotConstruct;
 }
 
 inline bool functionNameIsInScope(const Identifier& name, FunctionMode functionMode)
index e42d150..248d0ee 100644 (file)
@@ -82,6 +82,7 @@ enum JSTokenType {
     CLASSTOKEN,
     EXTENDS,
     SUPER,
+    AWAIT,
     OPENBRACE = 0,
     CLOSEBRACE,
     OPENPAREN,
@@ -113,8 +114,6 @@ enum JSTokenType {
     OREQUAL,
     DOTDOTDOT,
     ARROWFUNCTION,
-    // Untagged conditional keywords
-    AWAIT,
     LastUntaggedToken,
 
     // Begin tagged tokens