Skip to content
Permalink
Browse files
[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.

Canonical link: https://commits.webkit.org/176319@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201523 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Constellation committed May 31, 2016
1 parent 05576d4 commit c31c88516ff1212722baea65f767391d6f16a5e5
@@ -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
@@ -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);
}
@@ -158,6 +158,7 @@ class UnlinkedFunctionExecutable final : public JSCell {
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 @@ class UnlinkedFunctionExecutable final : public JSCell {
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;

0 comments on commit c31c885

Please sign in to comment.