Skip to content

Commit

Permalink
Enable lazy parsing for arrow functions
Browse files Browse the repository at this point in the history
Summary:
Store the required flags in the parser and lazy parse arrow functions.
The flags are stored in the JSParserImpl and restored based on whether
we've finished parsing an arrow or non-arrow function.

Reviewed By: tmikov

Differential Revision: D55992926

fbshipit-source-id: 174c60ee75ca905ad6b29bfe50a4c76e262e7770
  • Loading branch information
avp authored and facebook-github-bot committed May 30, 2024
1 parent 7278736 commit bee8b15
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 24 deletions.
6 changes: 3 additions & 3 deletions lib/Parser/JSParserImpl-flow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ Optional<ESTree::Node *> JSParserImpl::parseComponentDeclarationFlow(
return None;
}

SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this};

auto parsedBody = parseFunctionBody(
Param{}, false, false, false, JSLexer::AllowRegExp, true);
Expand Down Expand Up @@ -765,7 +765,7 @@ Optional<ESTree::Node *> JSParserImpl::parseHookDeclarationFlow(SMLoc start) {
return None;
}

SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this};

auto parsedBody = parseFunctionBody(
Param{}, false, false, false, JSLexer::AllowRegExp, true);
Expand Down Expand Up @@ -1186,7 +1186,7 @@ Optional<ESTree::Node *> JSParserImpl::parseDeclareClassFlow(SMLoc start) {
advance(JSLexer::GrammarContext::Type);

// NOTE: Class definition is always strict mode code.
SaveStrictModeAndSeenDirectives saveStrictMode{this};
SaveFunctionState saveStrictMode{this};
setStrictMode(true);

if (!need(
Expand Down
85 changes: 70 additions & 15 deletions lib/Parser/JSParserImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void JSParserImpl::initializeIdentifiers() {
valueIdent_ = lexer_.getIdentifier("value");
typeIdent_ = lexer_.getIdentifier("type");
asyncIdent_ = lexer_.getIdentifier("async");
argumentsIdent_ = lexer_.getIdentifier("arguments");
awaitIdent_ = lexer_.getIdentifier("await");
assertIdent_ = lexer_.getIdentifier("assert");

Expand Down Expand Up @@ -342,7 +343,7 @@ bool JSParserImpl::recursionDepthExceeded() {

Optional<ESTree::ProgramNode *> JSParserImpl::parseProgram() {
SMLoc startLoc = tok_->getStartLoc();
SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this};
ESTree::NodeList stmtList;

if (!parseStatementList(
Expand Down Expand Up @@ -495,7 +496,7 @@ Optional<ESTree::FunctionLikeNode *> JSParserImpl::parseFunctionHelper(
return None;
}

SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this};

// Grammar context to be used when lexing the closing brace.
auto grammarContext =
Expand Down Expand Up @@ -757,6 +758,9 @@ Optional<ESTree::BlockStatementNode *> JSParserImpl::parseFunctionBody(
body->paramYield = paramYield;
body->paramAwait = paramAwait;
body->bufferId = lexer_.getBufferId();
body->containsArrowFunctions = functionInfo.containsArrowFunctions;
body->mayContainArrowFunctionsUsingArguments =
functionInfo.mayContainArrowFunctionsUsingArguments;
return setLocation(startLoc, endLoc, body);
}
}
Expand All @@ -767,7 +771,11 @@ Optional<ESTree::BlockStatementNode *> JSParserImpl::parseFunctionBody(

if (pass_ == PreParse) {
preParsed_->functionInfo[(*body)->getStartLoc()] = PreParsedFunctionInfo{
(*body)->getEndLoc(), isStrictMode(), copySeenDirectives()};
(*body)->getEndLoc(),
isStrictMode(),
copySeenDirectives(),
containsArrowFunctions_,
mayContainArrowFunctionsUsingArguments_};
}

return body;
Expand Down Expand Up @@ -1162,7 +1170,10 @@ JSParserImpl::parseVariableDeclaration(Param param, SMLoc declLoc) {
auto debugLoc = advance().Start;

auto expr = parseAssignmentExpression(
param, AllowTypedArrowFunction::Yes, CoverTypedParameters::No);
param,
/* eagerly */ false,
AllowTypedArrowFunction::Yes,
CoverTypedParameters::No);
if (!expr)
return None;

Expand Down Expand Up @@ -2335,6 +2346,11 @@ Optional<ESTree::Node *> JSParserImpl::parsePrimaryExpression() {
return None;
return func.getValue();
}
if (isArrowFunction_ && LLVM_UNLIKELY(check(argumentsIdent_))) {
// Found an identifier 'arguments', so set this flag to conservatively
// assume that the function uses 'arguments'.
mayContainArrowFunctionsUsingArguments_ = true;
}
auto *res = setLocation(
tok_,
tok_,
Expand Down Expand Up @@ -2643,7 +2659,7 @@ Optional<ESTree::Node *> JSParserImpl::parsePropertyAssignment(bool eagerly) {
SMLoc startLoc = tok_->getStartLoc();
ESTree::NodePtr key = nullptr;

SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this};

bool computed = false;
bool generator = false;
Expand Down Expand Up @@ -4298,7 +4314,10 @@ Optional<ESTree::Node *> JSParserImpl::parseConditionalExpression(
&sm_, Subsystem::Parser};
CHECK_RECURSION;
auto optConsequent = parseAssignmentExpression(
ParamIn, AllowTypedArrowFunction::Yes, CoverTypedParameters::No);
ParamIn,
/* eagerly */ false,
AllowTypedArrowFunction::Yes,
CoverTypedParameters::No);
if (optConsequent && check(TokenKind::colon)) {
consequent = *optConsequent;
} else {
Expand All @@ -4319,7 +4338,10 @@ Optional<ESTree::Node *> JSParserImpl::parseConditionalExpression(
// Consume the '?' (either for the first time or after savePoint.restore()).
advance();
auto optConsequent = parseAssignmentExpression(
ParamIn, AllowTypedArrowFunction::No, CoverTypedParameters::No);
ParamIn,
/* eagerly */ false,
AllowTypedArrowFunction::No,
CoverTypedParameters::No);
if (!optConsequent)
return None;
consequent = *optConsequent;
Expand All @@ -4334,7 +4356,10 @@ Optional<ESTree::Node *> JSParserImpl::parseConditionalExpression(
return None;

auto optAlternate = parseAssignmentExpression(
param, AllowTypedArrowFunction::Yes, CoverTypedParameters::No);
param,
/* eagerly */ false,
AllowTypedArrowFunction::Yes,
CoverTypedParameters::No);
if (!optAlternate)
return None;
ESTree::Node *alternate = *optAlternate;
Expand Down Expand Up @@ -4405,6 +4430,7 @@ Optional<ESTree::YieldExpressionNode *> JSParserImpl::parseYieldExpression(

auto optArg = parseAssignmentExpression(
param.get(ParamIn),
/* eagerly */ false,
AllowTypedArrowFunction::Yes,
CoverTypedParameters::No);
if (!optArg)
Expand All @@ -4420,7 +4446,7 @@ Optional<ESTree::ClassDeclarationNode *> JSParserImpl::parseClassDeclaration(
Param param) {
assert(check(TokenKind::rw_class) && "class must start with 'class'");
// NOTE: Class definition is always strict mode code.
SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this};
setStrictMode(true);

SMLoc startLoc = advance().Start;
Expand Down Expand Up @@ -4476,7 +4502,7 @@ Optional<ESTree::ClassDeclarationNode *> JSParserImpl::parseClassDeclaration(
Optional<ESTree::ClassExpressionNode *> JSParserImpl::parseClassExpression() {
assert(check(TokenKind::rw_class) && "class must start with 'class'");
// NOTE: A class definition is always strict mode code.
SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this};
setStrictMode(true);

SMLoc start = advance().Start;
Expand Down Expand Up @@ -5296,6 +5322,7 @@ bool JSParserImpl::reparseArrowParameters(

Optional<ESTree::Node *> JSParserImpl::parseArrowFunctionExpression(
Param param,
bool forceEagerly,
ESTree::Node *leftExpr,
bool hasNewLine,
ESTree::Node *typeParams,
Expand Down Expand Up @@ -5324,7 +5351,8 @@ Optional<ESTree::Node *> JSParserImpl::parseArrowFunctionExpression(
if (!reparseArrowParameters(leftExpr, hasNewLine, paramList, isAsync))
return None;

SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
SaveFunctionState saveFunctionState{this, /* arrow */ true};

ESTree::Node *body;
bool expression;

Expand All @@ -5333,7 +5361,7 @@ Optional<ESTree::Node *> JSParserImpl::parseArrowFunctionExpression(
if (check(TokenKind::l_brace)) {
auto optBody = parseFunctionBody(
Param{},
true,
forceEagerly,
oldParamYield.get(),
argsParamAwait.get(),
JSLexer::AllowDiv,
Expand All @@ -5348,6 +5376,7 @@ Optional<ESTree::Node *> JSParserImpl::parseArrowFunctionExpression(
CHECK_RECURSION;
auto optConcise = parseAssignmentExpression(
param.get(ParamIn),
true,
allowTypedArrowFunction,
CoverTypedParameters::No,
nullptr);
Expand All @@ -5367,7 +5396,21 @@ Optional<ESTree::Node *> JSParserImpl::parseArrowFunctionExpression(
expression,
isAsync);

return setLocation(startLoc, getPrevTokenEndLoc(), arrow);
if (pass_ == PreParse) {
auto [it, inserted] = preParsed_->functionInfo.try_emplace(
startLoc,
PreParsedFunctionInfo{
body->getEndLoc(),
isStrictMode(),
copySeenDirectives(),
containsArrowFunctions_,
mayContainArrowFunctionsUsingArguments_,
});
(void)it;
assert(inserted);
}

return setLocation(startLoc, body->getEndLoc(), arrow);
}

Optional<ESTree::Node *> JSParserImpl::reparseAssignmentPattern(
Expand Down Expand Up @@ -5678,6 +5721,7 @@ Optional<ESTree::Node *> JSParserImpl::tryParseTypedAsyncArrowFunction(

return parseArrowFunctionExpression(
param,
/* eagerly */ false,
leftExpr,
hasNewLine,
typeParams,
Expand All @@ -5691,6 +5735,7 @@ Optional<ESTree::Node *> JSParserImpl::tryParseTypedAsyncArrowFunction(

Optional<ESTree::Node *> JSParserImpl::parseAssignmentExpression(
Param param,
bool forceEagerly,
AllowTypedArrowFunction allowTypedArrowFunction,
CoverTypedParameters coverTypedParameters,
ESTree::Node *typeParams) {
Expand All @@ -5704,7 +5749,7 @@ Optional<ESTree::Node *> JSParserImpl::parseAssignmentExpression(
explicit State() {}
};

auto parseHelper = [this](
auto parseHelper = [this, forceEagerly](
State &state,
Param param,
AllowTypedArrowFunction allowTypedArrowFunction,
Expand Down Expand Up @@ -5757,6 +5802,7 @@ Optional<ESTree::Node *> JSParserImpl::parseAssignmentExpression(
// typed arrow functions and attach the type parameters after the fact.
auto optAssign = parseAssignmentExpression(
param,
/* eagerly */ false,
AllowTypedArrowFunction::No,
CoverTypedParameters::No,
nullptr);
Expand All @@ -5773,6 +5819,7 @@ Optional<ESTree::Node *> JSParserImpl::parseAssignmentExpression(
typeParams = *optTypeParams;
optAssign = parseAssignmentExpression(
param,
/* eagerly */ false,
AllowTypedArrowFunction::Yes,
CoverTypedParameters::No,
typeParams);
Expand Down Expand Up @@ -5910,6 +5957,7 @@ Optional<ESTree::Node *> JSParserImpl::parseAssignmentExpression(
!lexer_.isNewLineBeforeCurrentToken()) {
return parseArrowFunctionExpression(
param,
forceEagerly,
*state.optLeftExpr,
state.hasNewLine,
typeParams,
Expand Down Expand Up @@ -6009,7 +6057,11 @@ Optional<ESTree::Node *> JSParserImpl::parseExpression(
CoverTypedParameters coverTypedParameters) {
SMLoc startLoc = tok_->getStartLoc();
auto optExpr = parseAssignmentExpression(
param, AllowTypedArrowFunction::Yes, coverTypedParameters, nullptr);
param,
/* eagerly */ false,
AllowTypedArrowFunction::Yes,
coverTypedParameters,
nullptr);
if (!optExpr)
return None;

Expand Down Expand Up @@ -6964,6 +7016,9 @@ Optional<ESTree::NodePtr> JSParserImpl::parseLazyFunction(
case ESTree::NodeKind::FunctionDeclaration:
return castNode(parseFunctionDeclaration(ParamReturn, true));

case ESTree::NodeKind::ArrowFunctionExpression:
return castNode(parseAssignmentExpression(ParamIn, true));

case ESTree::NodeKind::Property: {
auto node = parsePropertyAssignment(true);
assert(node && "Reparsing of property assignment failed");
Expand Down
Loading

0 comments on commit bee8b15

Please sign in to comment.