Changeset 201523 in webkit
- Timestamp:
- May 31, 2016 1:57:20 PM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r201520 r201523 1 2016-05-31 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 [JSC] Recover parser performance regression by async support 4 https://bugs.webkit.org/show_bug.cgi?id=158228 5 6 Reviewed by Saam Barati. 7 8 This patch recovers parser performance regression caused in r201481. 9 10 Compared to the version that reverts r201481, still ~1% regression remains. 11 But compared to ToT, this patch significantly improves the code-load performance. 12 13 In Linux x64 JSCOnly port, with GCC 5.3.1. 14 15 reverted v.s. patched. 16 reverted patched 17 18 closure 0.61805+-0.00376 ? 0.62280+-0.00525 ? 19 jquery 8.03778+-0.02114 8.03453+-0.04646 20 21 <geometric> 2.22883+-0.00836 ? 2.23688+-0.00995 ? might be 1.0036x slower 22 23 ToT v.s. patched. 24 baseline patched 25 26 closure 0.65490+-0.00351 ^ 0.62473+-0.00363 ^ definitely 1.0483x faster 27 jquery 8.25373+-0.06256 ^ 8.04701+-0.03455 ^ definitely 1.0257x faster 28 29 <geometric> 2.32488+-0.00921 ^ 2.24210+-0.00592 ^ definitely 1.0369x faster 30 31 * bytecode/UnlinkedFunctionExecutable.cpp: 32 (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): 33 * bytecode/UnlinkedFunctionExecutable.h: 34 Extend SourceParseMode. 35 36 * parser/Parser.cpp: 37 (JSC::Parser<LexerType>::parseInner): 38 (JSC::Parser<LexerType>::isArrowFunctionParameters): 39 Do not call `matchSpecIdentifier()` as much as we can. This greatly improves the performance. 40 41 (JSC::Parser<LexerType>::parseStatementListItem): 42 (JSC::Parser<LexerType>::parseStatement): 43 (JSC::Parser<LexerType>::parseFunctionParameters): 44 (JSC::Parser<LexerType>::parseFunctionInfo): 45 Do not touch `currentScope()->isGenerator()` even if it is unnecessary in parseFunctionInfo. 46 And accidental `syntaxChecker => context` changes are fixed. 47 48 (JSC::Parser<LexerType>::parseClass): 49 (JSC::Parser<LexerType>::parseExpressionOrLabelStatement): 50 (JSC::Parser<LexerType>::parseImportClauseItem): 51 (JSC::Parser<LexerType>::parseExportDeclaration): 52 (JSC::Parser<LexerType>::parseAssignmentExpression): 53 Do not use matchSpecIdentifier() in the hot paths. 54 55 (JSC::Parser<LexerType>::parseProperty): 56 (JSC::Parser<LexerType>::parsePrimaryExpression): 57 (JSC::Parser<LexerType>::parseMemberExpression): 58 (JSC::Parser<LexerType>::parseUnaryExpression): 59 (JSC::Parser<LexerType>::printUnexpectedTokenText): Deleted. 60 * parser/Parser.h: 61 (JSC::isIdentifierOrKeyword): 62 AWAIT shoud be one of the keywords. This AWAIT check is unnecessary. 63 64 (JSC::Parser::upperScope): 65 (JSC::Parser::matchSpecIdentifier): 66 Touching currentScope() and its member causes significant performance degradation. 67 We carefully remove the above access in the hot paths. 68 69 (JSC::Parser::isDisallowedIdentifierAwait): 70 * parser/ParserModes.h: 71 (JSC::SourceParseModeSet::SourceParseModeSet): 72 (JSC::SourceParseModeSet::contains): 73 (JSC::SourceParseModeSet::mergeSourceParseModes): 74 (JSC::isFunctionParseMode): 75 (JSC::isAsyncFunctionParseMode): 76 (JSC::isAsyncArrowFunctionParseMode): 77 (JSC::isAsyncFunctionWrapperParseMode): 78 (JSC::isAsyncFunctionBodyParseMode): 79 (JSC::isModuleParseMode): 80 (JSC::isProgramParseMode): 81 (JSC::constructAbilityForParseMode): 82 The parser frequently checks SourceParseMode. And variety of SourceParseMode becomes many. 83 So using switch onto SourceParseMode degrades the performance. Instead, we use bit tests to guard against 84 many SourceParseModes. We expect that this will be efficiently compiled into test & jmp. 85 86 * parser/ParserTokens.h: 87 Change AWAIT to one of the keywords, as the same to YIELD / LET. 88 1 89 2016-05-31 Saam Barati <sbarati@apple.com> 2 90 -
trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
r201481 r201523 92 92 , m_parameterCount(node->parameterCount()) 93 93 , m_features(0) 94 , m_sourceParseMode(node->parseMode()) 94 95 , m_isInStrictContext(node->isInStrictContext()) 95 96 , m_hasCapturedVariables(false) … … 100 101 , m_superBinding(static_cast<unsigned>(node->superBinding())) 101 102 , m_derivedContextType(static_cast<unsigned>(derivedContextType)) 102 , m_sourceParseMode(static_cast<unsigned>(node->parseMode()))103 103 , m_name(node->ident()) 104 104 , m_ecmaName(node->ecmaName()) … … 113 113 ASSERT(m_superBinding == static_cast<unsigned>(node->superBinding())); 114 114 ASSERT(m_derivedContextType == static_cast<unsigned>(derivedContextType)); 115 ASSERT(m_sourceParseMode == static_cast<unsigned>(node->parseMode()));116 115 117 116 m_parentScopeTDZVariables.swap(parentScopeTDZVariables); -
trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
r201481 r201523 159 159 unsigned m_parameterCount; 160 160 CodeFeatures m_features; 161 SourceParseMode m_sourceParseMode; 161 162 unsigned m_isInStrictContext : 1; 162 163 unsigned m_hasCapturedVariables : 1; … … 167 168 unsigned m_superBinding : 1; 168 169 unsigned m_derivedContextType: 2; 169 unsigned m_sourceParseMode : 4; // SourceParseMode170 170 171 171 WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall; -
trunk/Source/JavaScriptCore/parser/Parser.cpp
r201488 r201523 81 81 if (m_token.m_type & KeywordTokenFlag) \ 82 82 semanticFail("Cannot use the keyword '", getToken(), "' as a ", __VA_ARGS__); \ 83 if (isDisallowedIdentifierAwait(m_token)) \84 semanticFail("Can't use 'await' as a ", __VA_ARGS__, " ", disallowedIdentifierAwaitReason()); \85 83 } while (0) 86 84 … … 259 257 if (m_lexer->isReparsingFunction()) { 260 258 ParserFunctionInfo<ASTBuilder> functionInfo; 261 if ( parseMode == SourceParseMode::GeneratorBodyMode|| isAsyncFunctionBodyParseMode(parseMode))259 if (SourceParseModeSet(SourceParseMode::GeneratorBodyMode).contains(parseMode) || isAsyncFunctionBodyParseMode(parseMode)) 262 260 m_parameters = createGeneratorParameters(context); 263 261 else 264 262 m_parameters = parseFunctionParameters(context, parseMode, functionInfo); 265 263 266 if ( (parseMode == SourceParseMode::ArrowFunctionMode || parseMode == SourceParseMode::AsyncArrowFunctionMode) && !hasError()) {264 if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(parseMode) && !hasError()) { 267 265 // The only way we could have an error wile reparsing is if we run out of stack space. 268 266 RELEASE_ASSERT(match(ARROWFUNCTION)); … … 310 308 varDeclarations.markVariableAsCaptured(entry); 311 309 312 if ( parseMode == SourceParseMode::GeneratorWrapperFunctionMode|| isAsyncFunctionWrapperParseMode(parseMode)) {310 if (SourceParseModeSet(SourceParseMode::GeneratorWrapperFunctionMode).contains(parseMode) || isAsyncFunctionWrapperParseMode(parseMode)) { 313 311 if (scope->usedVariablesContains(m_vm->propertyNames->arguments.impl())) 314 312 context.propagateArgumentsUse(); … … 355 353 bool Parser<LexerType>::isArrowFunctionParameters() 356 354 { 357 bool isOpenParen = match(OPENPAREN); 358 bool isIdent = matchSpecIdentifier(); 359 360 if (!isOpenParen && !isIdent) 361 return false; 362 363 bool isArrowFunction = false; 364 SavePoint saveArrowFunctionPoint = createSavePoint(); 365 366 if (isIdent) { 367 next(); 368 isArrowFunction = match(ARROWFUNCTION); 369 } else { 370 RELEASE_ASSERT(isOpenParen); 371 next(); 355 if (match(OPENPAREN)) { 356 SavePoint saveArrowFunctionPoint = createSavePoint(); 357 next(); 358 bool isArrowFunction = false; 372 359 if (match(CLOSEPAREN)) { 373 360 next(); … … 381 368 unsigned parametersCount = 0; 382 369 isArrowFunction = parseFormalParameters(syntaxChecker, syntaxChecker.createFormalParameterList(), parametersCount) && consume(CLOSEPAREN) && match(ARROWFUNCTION); 383 370 384 371 popScope(fakeScope, syntaxChecker.NeedsFreeVariableInfo); 385 372 } 386 } 387 388 restoreSavePoint(saveArrowFunctionPoint); 389 390 return isArrowFunction; 373 restoreSavePoint(saveArrowFunctionPoint); 374 return isArrowFunction; 375 } 376 377 if (matchSpecIdentifier()) { 378 SavePoint saveArrowFunctionPoint = createSavePoint(); 379 next(); 380 bool isArrowFunction = match(ARROWFUNCTION); 381 restoreSavePoint(saveArrowFunctionPoint); 382 return isArrowFunction; 383 } 384 385 return false; 391 386 } 392 387 … … 601 596 // But we would like to enter parseVariableDeclaration and raise an error under the context of parseVariableDeclaration 602 597 // to raise consistent errors between "var", "const" and "let". 603 if (!(match(IDENT) || match( AWAIT) || match(LET) || match(YIELD)) && !match(OPENBRACE) && !match(OPENBRACKET))598 if (!(match(IDENT) || match(LET) || match(YIELD) || match(AWAIT)) && !match(OPENBRACE) && !match(OPENBRACKET)) 604 599 shouldParseVariableDeclaration = false; 605 600 restoreSavePoint(savePoint); … … 620 615 result = parseFunctionDeclaration(context); 621 616 break; 622 623 617 case IDENT: 624 if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) { 625 // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case, 626 // but could be mistakenly parsed as an AsyncFunctionExpression. 627 SavePoint savePoint = createSavePoint(); 628 next(); 629 if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) { 630 result = parseAsyncFunctionDeclaration(context); 631 break; 618 // FIXME: This branch contributes to a 1% octane code-load regression. 619 // https://bugs.webkit.org/show_bug.cgi?id=158211 620 if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async)) { 621 if (m_runtimeFlags.isAsyncAwaitEnabled()) { 622 // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case, 623 // but could be mistakenly parsed as an AsyncFunctionExpression. 624 SavePoint savePoint = createSavePoint(); 625 next(); 626 if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) { 627 result = parseAsyncFunctionDeclaration(context); 628 break; 629 } 630 restoreSavePoint(savePoint); 632 631 } 633 restoreSavePoint(savePoint);634 632 } 635 633 FALLTHROUGH; … … 1736 1734 // These tokens imply the end of a set of source elements 1737 1735 return 0; 1738 1739 1736 case IDENT: 1740 if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) { 1741 SavePoint savePoint = createSavePoint(); 1742 next(); 1743 if (match(FUNCTION) && !m_lexer->prevTerminator()) { 1744 const bool isAsync = true; 1745 result = parseFunctionDeclarationStatement(context, isAsync, parentAllowsFunctionDeclarationAsStatement); 1746 break; 1737 // FIXME: This branch contributes to a 1% octane code-load regression. 1738 // https://bugs.webkit.org/show_bug.cgi?id=158211 1739 if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async)) { 1740 if (m_runtimeFlags.isAsyncAwaitEnabled()) { 1741 SavePoint savePoint = createSavePoint(); 1742 next(); 1743 if (match(FUNCTION) && !m_lexer->prevTerminator()) { 1744 const bool isAsync = true; 1745 result = parseFunctionDeclarationStatement(context, isAsync, parentAllowsFunctionDeclarationAsStatement); 1746 break; 1747 } 1748 restoreSavePoint(savePoint); 1747 1749 } 1748 restoreSavePoint(savePoint);1749 1750 } 1750 1751 FALLTHROUGH; … … 1930 1931 template <typename LexerType> template <class TreeBuilder, class FunctionInfoType> typename TreeBuilder::FormalParameterList Parser<LexerType>::parseFunctionParameters(TreeBuilder& context, SourceParseMode mode, FunctionInfoType& functionInfo) 1931 1932 { 1932 RELEASE_ASSERT(mode != SourceParseMode::ProgramMode && mode != SourceParseMode::ModuleAnalyzeMode && mode != SourceParseMode::ModuleEvaluateMode);1933 ASSERT(!(SourceParseModeSet(SourceParseMode::ProgramMode, SourceParseMode::ModuleAnalyzeMode, SourceParseMode::ModuleEvaluateMode).contains(mode))); 1933 1934 TreeFormalParameterList parameterList = context.createFormalParameterList(); 1934 1935 SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Parameters); 1935 1936 1936 if ( mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode) {1937 if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(mode)) { 1937 1938 if (!matchSpecIdentifier() && !match(OPENPAREN)) { 1938 1939 semanticFailureDueToKeyword(stringForFunctionMode(mode), " name"); … … 2026 2027 RELEASE_ASSERT(isFunctionParseMode(mode)); 2027 2028 2028 bool upperScopeIsGenerator = currentScope()->isGenerator();2029 2029 bool isDisallowedAwaitFunctionName = isDisallowedIdentifierAwait(m_token); 2030 2030 const char* isDisallowedAwaitFunctionNameReason = isDisallowedAwaitFunctionName ? disallowedIdentifierAwaitReason() : nullptr; 2031 2031 2032 AutoPopScopeRef functionScope(this, pushScope()); 2032 2033 functionScope->setSourceParseMode(mode); … … 2067 2068 2068 2069 FunctionBodyType functionBodyType; 2069 if ( mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode)2070 if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(mode)) 2070 2071 functionBodyType = cachedInfo->isBodyArrowExpression ? ArrowFunctionBodyExpression : ArrowFunctionBodyBlock; 2071 2072 else … … 2110 2111 SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get()); 2111 2112 2112 if ( mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode) {2113 if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(mode)) { 2113 2114 startLocation = tokenLocation(); 2114 2115 functionInfo.startLine = tokenLine(); … … 2122 2123 { 2123 2124 SetForScope<bool> overrideAllowAwait(m_parserState.allowAwait, !isAsyncFunctionParseMode(mode)); 2124 parseFunctionParameters( context, mode, functionInfo);2125 parseFunctionParameters(syntaxChecker, mode, functionInfo); 2125 2126 } 2126 2127 … … 2155 2156 // 2156 2157 // The name of FunctionExpression and AsyncFunctionExpression can accept "yield" even in the context of generator. 2157 if (functionDefinitionType == FunctionDefinitionType::Expression && (mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::AsyncFunctionMode)) 2158 upperScopeIsGenerator = false; 2158 bool upperScopeIsGenerator = false; 2159 if (!(functionDefinitionType == FunctionDefinitionType::Expression && SourceParseModeSet(SourceParseMode::NormalFunctionMode, SourceParseMode::AsyncFunctionMode).contains(mode))) 2160 upperScopeIsGenerator = upperScope(1)->isGenerator(); 2159 2161 2160 2162 if (matchSpecIdentifier(upperScopeIsGenerator)) { … … 2171 2173 failIfTrueIfStrict(functionScope->declareCallee(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode"); 2172 2174 } else if (requirements == FunctionNeedsName) { 2173 semanticFailIfTrue(match(OPENPAREN) && mode == SourceParseMode::NormalFunctionMode, "Function statements must have a name"); 2174 semanticFailIfTrue(match(OPENPAREN) && mode == SourceParseMode::AsyncFunctionMode, "Async function statements must have a name"); 2175 if (match(OPENPAREN)) { 2176 semanticFailIfTrue(mode == SourceParseMode::NormalFunctionMode, "Function statements must have a name"); 2177 semanticFailIfTrue(mode == SourceParseMode::AsyncFunctionMode, "Async function statements must have a name"); 2178 } 2175 2179 semanticFailureDueToKeyword(stringForFunctionMode(mode), " name"); 2176 2180 failDueToUnexpectedToken(); … … 2190 2194 { 2191 2195 SetForScope<bool> overrideAllowAwait(m_parserState.allowAwait, !isAsyncFunctionParseMode(mode)); 2192 parseFunctionParameters( context, mode, functionInfo);2196 parseFunctionParameters(syntaxChecker, mode, functionInfo); 2193 2197 propagateError(); 2194 2198 } … … 2236 2240 }; 2237 2241 2238 if ( mode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(mode)) {2242 if (UNLIKELY((SourceParseModeSet(SourceParseMode::GeneratorWrapperFunctionMode).contains(mode)) || isAsyncFunctionWrapperParseMode(mode))) { 2239 2243 AutoPopScopeRef generatorBodyScope(this, pushScope()); 2240 2244 SourceParseMode innerParseMode = SourceParseMode::GeneratorBodyMode; … … 2262 2266 context.setEndOffset(functionInfo.body, m_lexer->currentOffset()); 2263 2267 if (functionScope->strictMode() && functionInfo.name) { 2264 RELEASE_ASSERT( mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode|| isAsyncFunctionWrapperParseMode(mode));2268 RELEASE_ASSERT((SourceParseModeSet(SourceParseMode::NormalFunctionMode, SourceParseMode::MethodMode, SourceParseMode::ArrowFunctionMode, SourceParseMode::GeneratorBodyMode, SourceParseMode::GeneratorWrapperFunctionMode).contains(mode)) || isAsyncFunctionWrapperParseMode(mode)); 2265 2269 semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode"); 2266 2270 semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode"); … … 2476 2480 bool isGenerator = false; 2477 2481 bool isAsyncMethod = false; 2478 2479 2482 if (consume(TIMES)) 2480 2483 isGenerator = true; … … 2488 2491 next(); 2489 2492 break; 2493 case IDENT: 2490 2494 case AWAIT: 2491 case IDENT:2492 2495 ident = m_token.m_data.ident; 2493 2496 ASSERT(ident); … … 2496 2499 isGetter = *ident == propertyNames.get; 2497 2500 isSetter = *ident == propertyNames.set; 2498 if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && !isAsyncMethod && *ident == propertyNames.async && !m_lexer->prevTerminator())) { 2499 isAsyncMethod = true; 2500 goto parseMethod; 2501 if (UNLIKELY(!isAsyncMethod && *ident == propertyNames.async && !m_lexer->prevTerminator())) { 2502 if (m_runtimeFlags.isAsyncAwaitEnabled()) { 2503 isAsyncMethod = true; 2504 goto parseMethod; 2505 } 2501 2506 } 2502 2507 } … … 2619 2624 return context.createExprStatement(location, expression, start, m_lastTokenEndPosition.line); 2620 2625 } 2626 // FIXME: This branch contributes to a 1% octane code-load regression. 2627 // https://bugs.webkit.org/show_bug.cgi?id=158211 2628 if (UNLIKELY(match(AWAIT))) 2629 semanticFailIfTrue(isDisallowedIdentifierAwait(m_token), "Can't use 'await' as a label ", disallowedIdentifierAwaitReason()); 2621 2630 const Identifier* ident = m_token.m_data.ident; 2622 const bool isDisallowedLabelAwait = isDisallowedIdentifierAwait(m_token);2623 2631 JSTextPosition end = tokenEndPosition(); 2624 2632 next(); 2625 2633 consumeOrFail(COLON, "Labels must be followed by a ':'"); 2626 semanticFailIfTrue(isDisallowedLabelAwait, "Can't use 'await' as a label ", disallowedIdentifierAwaitReason());2627 2634 if (!m_syntaxAlreadyValidated) { 2628 2635 // This is O(N^2) over the current list of consecutive labels, but I … … 2859 2866 } 2860 2867 2868 semanticFailIfTrue(localNameToken.m_type == AWAIT, "Cannot use 'await' as an imported binding name"); 2861 2869 semanticFailIfTrue(localNameToken.m_type & KeywordTokenFlag, "Cannot use keyword as imported binding name"); 2862 semanticFailIfTrue(localNameToken.m_type == AWAIT, "Cannot use 'await' as an imported binding name");2863 2870 DeclarationResultMask declarationResult = declareVariable(localName, DeclarationType::ConstDeclaration, (specifierType == ImportSpecifierType::NamespaceImport) ? DeclarationImportType::ImportedNamespace : DeclarationImportType::Imported); 2864 2871 if (declarationResult != DeclarationResult::Valid) { … … 3003 3010 SavePoint savePoint = createSavePoint(); 3004 3011 3005 if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) { 3006 next(); 3007 if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) 3008 isAsyncFunctionExport = true; 3009 else 3010 restoreSavePoint(savePoint); 3012 if (UNLIKELY(matchContextualKeyword(m_vm->propertyNames->async))) { 3013 if (m_runtimeFlags.isAsyncAwaitEnabled()) { 3014 next(); 3015 if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) 3016 isAsyncFunctionExport = true; 3017 else 3018 restoreSavePoint(savePoint); 3019 } 3011 3020 } 3012 3021 … … 3154 3163 3155 3164 default: 3156 if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) { 3157 next(); 3158 semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator"); 3159 result = parseAsyncFunctionDeclaration(context, ExportType::Exported); 3160 break; 3165 if (UNLIKELY(matchContextualKeyword(m_vm->propertyNames->async))) { 3166 if (m_runtimeFlags.isAsyncAwaitEnabled()) { 3167 next(); 3168 semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator"); 3169 result = parseAsyncFunctionDeclaration(context, ExportType::Exported); 3170 break; 3171 } 3161 3172 } 3173 3162 3174 failWithMessage("Expected either a declaration or a variable statement"); 3163 3175 break; … … 3224 3236 3225 3237 failIfStackOverflow(); 3238 3239 if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator())) 3240 return parseYieldExpression(context); 3241 3226 3242 JSTextPosition start = tokenStartPosition(); 3227 3243 JSTokenLocation location(tokenLocation()); … … 3230 3246 bool maybeAssignmentPattern = match(OPENBRACE) || match(OPENBRACKET); 3231 3247 bool wasOpenParen = match(OPENPAREN); 3232 bool isValidArrowFunctionStart = match(OPENPAREN) || matchSpecIdentifier(); 3248 // Do not use matchSpecIdentifier() here since it is slower than isIdentifierOrKeyword. 3249 // Whether spec identifier is will be validated by isArrowFunctionParameters(). 3250 bool wasIdentifierOrKeyword = isIdentifierOrKeyword(m_token); 3251 bool maybeValidArrowFunctionStart = wasOpenParen || wasIdentifierOrKeyword; 3233 3252 SavePoint savePoint = createSavePoint(); 3234 3253 size_t usedVariablesSize = 0; 3235 if (wasOpenParen || UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) { 3254 3255 // FIXME: This branch contributes to a 1% octane code-load regression. 3256 // https://bugs.webkit.org/show_bug.cgi?id=158211 3257 if (wasOpenParen || (wasIdentifierOrKeyword && m_runtimeFlags.isAsyncAwaitEnabled() && UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async))) { 3236 3258 usedVariablesSize = currentScope()->currentUsedVariablesSize(); 3237 3259 currentScope()->pushUsedVariableSet(); 3238 3260 } 3239 3261 3240 if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator()))3241 return parseYieldExpression(context);3242 3243 3262 TreeExpression lhs = parseConditionalExpression(context); 3244 3263 3245 if ( isValidArrowFunctionStart && !match(EOFTOK)) {3264 if (maybeValidArrowFunctionStart && !match(EOFTOK)) { 3246 3265 bool isArrowFunctionToken = match(ARROWFUNCTION); 3247 3266 if (!lhs || isArrowFunctionToken) { … … 3484 3503 bool isClassProperty = false; 3485 3504 bool isAsyncMethod = false; 3486 3487 3505 if (consume(TIMES)) 3488 3506 isGenerator = true; … … 3491 3509 switch (m_token.m_type) { 3492 3510 namedProperty: 3511 case IDENT: 3493 3512 case AWAIT: 3494 case IDENT:3495 3513 wasIdent = true; 3496 3514 FALLTHROUGH; … … 3543 3561 failIfTrue(m_lexer->prevTerminator(), "Expected a property name following keyword 'async'"); 3544 3562 goto parseProperty; 3545 } 3546 else 3563 } else 3547 3564 failWithMessage("Expected a ':' following the property name '", ident->impl(), "'"); 3548 3565 return parseGetterSetter(context, complete, type, getterOrSetterStartOffset, ConstructorKind::None, isClassProperty); … … 3966 3983 JSTokenLocation location(tokenLocation()); 3967 3984 next(); 3968 if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && match(FUNCTION) && !m_lexer->prevTerminator() && *ident == m_vm->propertyNames->async)) 3969 return parseAsyncFunctionExpression(context); 3985 // FIXME: This branch contributes to a 1% octane code-load regression. 3986 // https://bugs.webkit.org/show_bug.cgi?id=158211 3987 if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator() && *ident == m_vm->propertyNames->async)) { 3988 if (m_runtimeFlags.isAsyncAwaitEnabled()) 3989 return parseAsyncFunctionExpression(context); 3990 } 3970 3991 currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident); 3971 3992 m_parserState.lastIdentifier = ident; … … 4162 4183 } 4163 4184 } else if (!baseIsNewTarget) { 4164 currentFunctionScope()->setNeedsSuperBinding(); 4185 // FIXME: This branch contributes to a 1% octane code-load regression. 4186 // https://bugs.webkit.org/show_bug.cgi?id=158211 4165 4187 const bool isAsync = matchContextualKeyword(m_vm->propertyNames->async); 4166 4188 base = parsePrimaryExpression(context); … … 4257 4279 break; 4258 4280 } 4259 4260 4281 default: 4261 4282 goto endMemberExpression; … … 4326 4347 unsigned lastOperator = 0; 4327 4348 4328 if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && match(AWAIT) && currentFunctionScope()->isAsyncFunction())) 4329 return parseAwaitExpression(context); 4349 // FIXME: This branch contributes to a 1% octane code-load regression. 4350 // https://bugs.webkit.org/show_bug.cgi?id=158211 4351 if (UNLIKELY(match(AWAIT))) { 4352 if (m_runtimeFlags.isAsyncAwaitEnabled() && currentFunctionScope()->isAsyncFunction()) 4353 return parseAwaitExpression(context); 4354 } 4330 4355 4331 4356 while (isUnaryOp(m_token.m_type)) { … … 4510 4535 return; 4511 4536 4512 case AWAIT:4513 4537 case IDENT: 4514 4538 out.print("Unexpected identifier '", getToken(), "'"); -
trunk/Source/JavaScriptCore/parser/Parser.h
r201481 r201523 127 127 ALWAYS_INLINE static bool isIdentifierOrKeyword(const JSToken& token) 128 128 { 129 return token.m_type == IDENT || token.m_type == AWAIT || token.m_type& KeywordTokenFlag;129 return token.m_type == IDENT || token.m_type & KeywordTokenFlag; 130 130 } 131 131 … … 1073 1073 ALWAYS_INLINE bool isEvalOrArguments(const Identifier* ident) { return isEvalOrArgumentsIdentifier(m_vm, ident); } 1074 1074 1075 ScopeRef upperScope(unsigned n) 1076 { 1077 ASSERT(m_scopeStack.size() >= (1 + n)); 1078 return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1 - n); 1079 } 1080 1075 1081 ScopeRef currentScope() 1076 1082 { … … 1446 1452 ALWAYS_INLINE bool matchSpecIdentifier(bool inGenerator) 1447 1453 { 1448 return match(IDENT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(inGenerator) || match(AWAIT); 1449 } 1450 1454 return match(IDENT) || match(AWAIT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(inGenerator); 1455 } 1456 1457 // http://ecma-international.org/ecma-262/6.0/#sec-generator-function-definitions-static-semantics-early-errors 1451 1458 ALWAYS_INLINE bool matchSpecIdentifier() 1452 1459 { 1453 return match SpecIdentifier(currentScope()->isGenerator());1460 return match(IDENT) || match(AWAIT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(currentScope()->isGenerator()); 1454 1461 } 1455 1462 … … 1568 1575 bool isDisallowedIdentifierAwait(const JSToken& token) 1569 1576 { 1570 return token.m_type == AWAIT && ( currentScope()->isAsyncFunctionBoundary() || currentScope()->isModule() || !m_parserState.allowAwait);1577 return token.m_type == AWAIT && (!m_parserState.allowAwait || currentScope()->isAsyncFunctionBoundary() || currentScope()->isModule()); 1571 1578 } 1572 1579 -
trunk/Source/JavaScriptCore/parser/ParserModes.h
r201481 r201523 44 44 enum class FunctionMode { FunctionExpression, FunctionDeclaration, MethodDefinition }; 45 45 46 enum class SourceParseMode : uint8_t { 47 NormalFunctionMode, 48 GeneratorBodyMode, 49 GeneratorWrapperFunctionMode, 50 GetterMode, 51 SetterMode, 52 MethodMode, 53 ArrowFunctionMode, 54 AsyncFunctionBodyMode, 55 AsyncArrowFunctionBodyMode, 56 AsyncFunctionMode, 57 AsyncMethodMode, 58 AsyncArrowFunctionMode, 59 ProgramMode, 60 ModuleAnalyzeMode, 61 ModuleEvaluateMode 46 // When you add a new source parse mode, do not forget to ensure that the predicates defined in this 47 // file work with the newly added mode. 48 enum class SourceParseMode : uint16_t { 49 NormalFunctionMode = 0b0000000000000001, 50 GeneratorBodyMode = 0b0000000000000010, 51 GeneratorWrapperFunctionMode = 0b0000000000000100, 52 GetterMode = 0b0000000000001000, 53 SetterMode = 0b0000000000010000, 54 MethodMode = 0b0000000000100000, 55 ArrowFunctionMode = 0b0000000001000000, 56 AsyncFunctionBodyMode = 0b0000000010000000, 57 AsyncArrowFunctionBodyMode = 0b0000000100000000, 58 AsyncFunctionMode = 0b0000001000000000, 59 AsyncMethodMode = 0b0000010000000000, 60 AsyncArrowFunctionMode = 0b0000100000000000, 61 ProgramMode = 0b0001000000000000, 62 ModuleAnalyzeMode = 0b0010000000000000, 63 ModuleEvaluateMode = 0b0100000000000000, 62 64 }; 63 65 64 inline bool isFunctionParseMode(SourceParseMode parseMode) 65 { 66 switch (parseMode) { 67 case SourceParseMode::NormalFunctionMode: 68 case SourceParseMode::GeneratorBodyMode: 69 case SourceParseMode::GeneratorWrapperFunctionMode: 70 case SourceParseMode::GetterMode: 71 case SourceParseMode::SetterMode: 72 case SourceParseMode::MethodMode: 73 case SourceParseMode::ArrowFunctionMode: 74 case SourceParseMode::AsyncFunctionBodyMode: 75 case SourceParseMode::AsyncFunctionMode: 76 case SourceParseMode::AsyncMethodMode: 77 case SourceParseMode::AsyncArrowFunctionMode: 78 case SourceParseMode::AsyncArrowFunctionBodyMode: 79 return true; 80 81 case SourceParseMode::ProgramMode: 82 case SourceParseMode::ModuleAnalyzeMode: 83 case SourceParseMode::ModuleEvaluateMode: 84 return false; 85 } 86 RELEASE_ASSERT_NOT_REACHED(); 87 return false; 88 } 89 90 inline bool isAsyncFunctionParseMode(SourceParseMode parseMode) 91 { 92 switch (parseMode) { 93 case SourceParseMode::AsyncFunctionBodyMode: 94 case SourceParseMode::AsyncArrowFunctionBodyMode: 95 case SourceParseMode::AsyncFunctionMode: 96 case SourceParseMode::AsyncMethodMode: 97 case SourceParseMode::AsyncArrowFunctionMode: 98 return true; 99 100 case SourceParseMode::NormalFunctionMode: 101 case SourceParseMode::GeneratorBodyMode: 102 case SourceParseMode::GeneratorWrapperFunctionMode: 103 case SourceParseMode::GetterMode: 104 case SourceParseMode::SetterMode: 105 case SourceParseMode::MethodMode: 106 case SourceParseMode::ArrowFunctionMode: 107 case SourceParseMode::ModuleAnalyzeMode: 108 case SourceParseMode::ModuleEvaluateMode: 109 case SourceParseMode::ProgramMode: 110 return false; 111 } 112 RELEASE_ASSERT_NOT_REACHED(); 113 return false; 114 } 115 116 inline bool isAsyncArrowFunctionParseMode(SourceParseMode parseMode) 117 { 118 switch (parseMode) { 119 case SourceParseMode::AsyncArrowFunctionMode: 120 case SourceParseMode::AsyncArrowFunctionBodyMode: 121 return true; 122 123 case SourceParseMode::NormalFunctionMode: 124 case SourceParseMode::GeneratorBodyMode: 125 case SourceParseMode::GeneratorWrapperFunctionMode: 126 case SourceParseMode::GetterMode: 127 case SourceParseMode::SetterMode: 128 case SourceParseMode::MethodMode: 129 case SourceParseMode::ArrowFunctionMode: 130 case SourceParseMode::ModuleAnalyzeMode: 131 case SourceParseMode::ModuleEvaluateMode: 132 case SourceParseMode::AsyncFunctionBodyMode: 133 case SourceParseMode::AsyncMethodMode: 134 case SourceParseMode::AsyncFunctionMode: 135 case SourceParseMode::ProgramMode: 136 return false; 137 } 138 139 RELEASE_ASSERT_NOT_REACHED(); 140 return false; 141 } 142 143 inline bool isAsyncFunctionWrapperParseMode(SourceParseMode parseMode) 144 { 145 switch (parseMode) { 146 case SourceParseMode::AsyncFunctionMode: 147 case SourceParseMode::AsyncMethodMode: 148 case SourceParseMode::AsyncArrowFunctionMode: 149 return true; 150 151 case SourceParseMode::AsyncFunctionBodyMode: 152 case SourceParseMode::AsyncArrowFunctionBodyMode: 153 case SourceParseMode::NormalFunctionMode: 154 case SourceParseMode::GeneratorBodyMode: 155 case SourceParseMode::GeneratorWrapperFunctionMode: 156 case SourceParseMode::GetterMode: 157 case SourceParseMode::SetterMode: 158 case SourceParseMode::MethodMode: 159 case SourceParseMode::ArrowFunctionMode: 160 case SourceParseMode::ModuleAnalyzeMode: 161 case SourceParseMode::ModuleEvaluateMode: 162 case SourceParseMode::ProgramMode: 163 return false; 164 } 165 RELEASE_ASSERT_NOT_REACHED(); 166 return false; 167 } 168 169 inline bool isAsyncFunctionBodyParseMode(SourceParseMode parseMode) 170 { 171 switch (parseMode) { 172 case SourceParseMode::AsyncFunctionBodyMode: 173 case SourceParseMode::AsyncArrowFunctionBodyMode: 174 return true; 175 176 case SourceParseMode::NormalFunctionMode: 177 case SourceParseMode::GeneratorBodyMode: 178 case SourceParseMode::GeneratorWrapperFunctionMode: 179 case SourceParseMode::GetterMode: 180 case SourceParseMode::SetterMode: 181 case SourceParseMode::MethodMode: 182 case SourceParseMode::ArrowFunctionMode: 183 case SourceParseMode::AsyncFunctionMode: 184 case SourceParseMode::AsyncMethodMode: 185 case SourceParseMode::AsyncArrowFunctionMode: 186 case SourceParseMode::ModuleAnalyzeMode: 187 case SourceParseMode::ModuleEvaluateMode: 188 case SourceParseMode::ProgramMode: 189 return false; 190 } 191 RELEASE_ASSERT_NOT_REACHED(); 192 return false; 193 } 194 195 inline bool isModuleParseMode(SourceParseMode parseMode) 196 { 197 switch (parseMode) { 198 case SourceParseMode::ModuleAnalyzeMode: 199 case SourceParseMode::ModuleEvaluateMode: 200 return true; 201 202 case SourceParseMode::NormalFunctionMode: 203 case SourceParseMode::GeneratorBodyMode: 204 case SourceParseMode::GeneratorWrapperFunctionMode: 205 case SourceParseMode::GetterMode: 206 case SourceParseMode::SetterMode: 207 case SourceParseMode::MethodMode: 208 case SourceParseMode::ArrowFunctionMode: 209 case SourceParseMode::AsyncFunctionBodyMode: 210 case SourceParseMode::AsyncFunctionMode: 211 case SourceParseMode::AsyncMethodMode: 212 case SourceParseMode::AsyncArrowFunctionMode: 213 case SourceParseMode::AsyncArrowFunctionBodyMode: 214 case SourceParseMode::ProgramMode: 215 return false; 216 } 217 RELEASE_ASSERT_NOT_REACHED(); 218 return false; 219 } 220 221 inline bool isProgramParseMode(SourceParseMode parseMode) 222 { 223 switch (parseMode) { 224 case SourceParseMode::ProgramMode: 225 return true; 226 227 case SourceParseMode::NormalFunctionMode: 228 case SourceParseMode::GeneratorBodyMode: 229 case SourceParseMode::GeneratorWrapperFunctionMode: 230 case SourceParseMode::GetterMode: 231 case SourceParseMode::SetterMode: 232 case SourceParseMode::MethodMode: 233 case SourceParseMode::ArrowFunctionMode: 234 case SourceParseMode::AsyncFunctionBodyMode: 235 case SourceParseMode::AsyncFunctionMode: 236 case SourceParseMode::AsyncMethodMode: 237 case SourceParseMode::AsyncArrowFunctionMode: 238 case SourceParseMode::AsyncArrowFunctionBodyMode: 239 case SourceParseMode::ModuleAnalyzeMode: 240 case SourceParseMode::ModuleEvaluateMode: 241 return false; 242 } 243 RELEASE_ASSERT_NOT_REACHED(); 244 return false; 245 } 246 247 inline ConstructAbility constructAbilityForParseMode(SourceParseMode parseMode) 248 { 249 switch (parseMode) { 250 case SourceParseMode::NormalFunctionMode: 66 class SourceParseModeSet { 67 public: 68 template<typename... Modes> 69 SourceParseModeSet(Modes... args) 70 : m_mask(mergeSourceParseModes(args...)) 71 { 72 } 73 74 ALWAYS_INLINE bool contains(SourceParseMode mode) 75 { 76 return static_cast<unsigned>(mode) & m_mask; 77 } 78 79 private: 80 ALWAYS_INLINE static unsigned mergeSourceParseModes(SourceParseMode mode) 81 { 82 return static_cast<unsigned>(mode); 83 } 84 85 template<typename... Rest> 86 ALWAYS_INLINE static unsigned mergeSourceParseModes(SourceParseMode mode, Rest... rest) 87 { 88 return static_cast<unsigned>(mode) | mergeSourceParseModes(rest...); 89 } 90 91 const unsigned m_mask; 92 }; 93 94 ALWAYS_INLINE bool isFunctionParseMode(SourceParseMode parseMode) 95 { 96 return SourceParseModeSet( 97 SourceParseMode::NormalFunctionMode, 98 SourceParseMode::GeneratorBodyMode, 99 SourceParseMode::GeneratorWrapperFunctionMode, 100 SourceParseMode::GetterMode, 101 SourceParseMode::SetterMode, 102 SourceParseMode::MethodMode, 103 SourceParseMode::ArrowFunctionMode, 104 SourceParseMode::AsyncFunctionBodyMode, 105 SourceParseMode::AsyncFunctionMode, 106 SourceParseMode::AsyncMethodMode, 107 SourceParseMode::AsyncArrowFunctionMode, 108 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode); 109 } 110 111 ALWAYS_INLINE bool isAsyncFunctionParseMode(SourceParseMode parseMode) 112 { 113 return SourceParseModeSet( 114 SourceParseMode::AsyncFunctionBodyMode, 115 SourceParseMode::AsyncFunctionMode, 116 SourceParseMode::AsyncMethodMode, 117 SourceParseMode::AsyncArrowFunctionMode, 118 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode); 119 } 120 121 ALWAYS_INLINE bool isAsyncArrowFunctionParseMode(SourceParseMode parseMode) 122 { 123 return SourceParseModeSet( 124 SourceParseMode::AsyncArrowFunctionMode, 125 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode); 126 } 127 128 ALWAYS_INLINE bool isAsyncFunctionWrapperParseMode(SourceParseMode parseMode) 129 { 130 return SourceParseModeSet( 131 SourceParseMode::AsyncArrowFunctionMode, 132 SourceParseMode::AsyncFunctionMode, 133 SourceParseMode::AsyncMethodMode).contains(parseMode); 134 } 135 136 ALWAYS_INLINE bool isAsyncFunctionBodyParseMode(SourceParseMode parseMode) 137 { 138 return SourceParseModeSet( 139 SourceParseMode::AsyncFunctionBodyMode, 140 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode); 141 } 142 143 ALWAYS_INLINE bool isModuleParseMode(SourceParseMode parseMode) 144 { 145 return SourceParseModeSet( 146 SourceParseMode::ModuleAnalyzeMode, 147 SourceParseMode::ModuleEvaluateMode).contains(parseMode); 148 } 149 150 ALWAYS_INLINE bool isProgramParseMode(SourceParseMode parseMode) 151 { 152 return SourceParseModeSet(SourceParseMode::ProgramMode).contains(parseMode); 153 } 154 155 ALWAYS_INLINE ConstructAbility constructAbilityForParseMode(SourceParseMode parseMode) 156 { 157 if (parseMode == SourceParseMode::NormalFunctionMode) 251 158 return ConstructAbility::CanConstruct; 252 253 case SourceParseMode::GeneratorBodyMode: 254 case SourceParseMode::GeneratorWrapperFunctionMode: 255 case SourceParseMode::GetterMode: 256 case SourceParseMode::SetterMode: 257 case SourceParseMode::MethodMode: 258 case SourceParseMode::ArrowFunctionMode: 259 case SourceParseMode::AsyncFunctionBodyMode: 260 case SourceParseMode::AsyncArrowFunctionBodyMode: 261 case SourceParseMode::AsyncFunctionMode: 262 case SourceParseMode::AsyncMethodMode: 263 case SourceParseMode::AsyncArrowFunctionMode: 264 return ConstructAbility::CannotConstruct; 265 266 case SourceParseMode::ProgramMode: 267 case SourceParseMode::ModuleAnalyzeMode: 268 case SourceParseMode::ModuleEvaluateMode: 269 break; 270 } 271 RELEASE_ASSERT_NOT_REACHED(); 272 return ConstructAbility::CanConstruct; 159 return ConstructAbility::CannotConstruct; 273 160 } 274 161 -
trunk/Source/JavaScriptCore/parser/ParserTokens.h
r201481 r201523 83 83 EXTENDS, 84 84 SUPER, 85 AWAIT, 85 86 OPENBRACE = 0, 86 87 CLOSEBRACE, … … 114 115 DOTDOTDOT, 115 116 ARROWFUNCTION, 116 // Untagged conditional keywords117 AWAIT,118 117 LastUntaggedToken, 119 118
Note: See TracChangeset
for help on using the changeset viewer.