Commit 69e36a95 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Parser] Remove aborting of preparsing for trivial long functions.

Real world websites don't benifit from aborting preparsing to eagerly compile
long trivial functions, and it adds unecessary complexity to the parser and
doesn't work well with bytecode flushing, so we remove it.

Perf Sheriffs: this is expected to regress the MandreelLatency benchmark on
Octane.

BUG=v8:8395

Change-Id: Ia60cd67d4dd100376d2a366939a1d2a97cbc2b0d
Reviewed-on: https://chromium-review.googlesource.com/c/1394297
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58568}
parent 09534392
...@@ -336,8 +336,6 @@ class ParserBase { ...@@ -336,8 +336,6 @@ class ParserBase {
friend class v8::internal::ExpressionParsingScope<ParserTypes<Impl>>; friend class v8::internal::ExpressionParsingScope<ParserTypes<Impl>>;
friend class v8::internal::ArrowHeadParsingScope<ParserTypes<Impl>>; friend class v8::internal::ArrowHeadParsingScope<ParserTypes<Impl>>;
enum LazyParsingResult { kLazyParsingComplete, kLazyParsingAborted };
enum VariableDeclarationContext { enum VariableDeclarationContext {
kStatementListItem, kStatementListItem,
kStatement, kStatement,
...@@ -1082,26 +1080,12 @@ class ParserBase { ...@@ -1082,26 +1080,12 @@ class ParserBase {
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
FunctionBodyType body_type); FunctionBodyType body_type);
// Under some circumstances, we allow preparsing to abort if the preparsed
// function is "long and trivial", and fully parse instead. Our current
// definition of "long and trivial" is:
// - over kLazyParseTrialLimit statements
// - all starting with an identifier (i.e., no if, for, while, etc.)
static const int kLazyParseTrialLimit = 200;
// TODO(nikolaos, marja): The first argument should not really be passed // TODO(nikolaos, marja): The first argument should not really be passed
// by value. The method is expected to add the parsed statements to the // by value. The method is expected to add the parsed statements to the
// list. This works because in the case of the parser, StatementListT is // list. This works because in the case of the parser, StatementListT is
// a pointer whereas the preparser does not really modify the body. // a pointer whereas the preparser does not really modify the body.
V8_INLINE void ParseStatementList(StatementListT* body, V8_INLINE void ParseStatementList(StatementListT* body,
Token::Value end_token) { Token::Value end_token);
LazyParsingResult result = ParseStatementList(body, end_token, false);
USE(result);
DCHECK_EQ(result, kLazyParsingComplete);
}
V8_INLINE LazyParsingResult ParseStatementList(StatementListT* body,
Token::Value end_token,
bool may_abort);
StatementT ParseStatementListItem(); StatementT ParseStatementListItem();
StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseStatement(ZonePtrList<const AstRawString>* labels,
...@@ -4057,11 +4041,10 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( ...@@ -4057,11 +4041,10 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// parameters. // parameters.
int dummy_num_parameters = -1; int dummy_num_parameters = -1;
DCHECK_NE(kind & FunctionKind::kArrowFunction, 0); DCHECK_NE(kind & FunctionKind::kArrowFunction, 0);
FunctionLiteral::EagerCompileHint hint;
bool did_preparse_successfully = impl()->SkipFunction( bool did_preparse_successfully = impl()->SkipFunction(
nullptr, kind, FunctionLiteral::kAnonymousExpression, nullptr, kind, FunctionLiteral::kAnonymousExpression,
formal_parameters.scope, &dummy_num_parameters, formal_parameters.scope, &dummy_num_parameters,
&produced_preparsed_scope_data, false, &hint); &produced_preparsed_scope_data);
DCHECK_NULL(produced_preparsed_scope_data); DCHECK_NULL(produced_preparsed_scope_data);
...@@ -4497,9 +4480,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic() { ...@@ -4497,9 +4480,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic() {
} }
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::LazyParsingResult void ParserBase<Impl>::ParseStatementList(StatementListT* body,
ParserBase<Impl>::ParseStatementList(StatementListT* body, Token::Value end_token) {
Token::Value end_token, bool may_abort) {
// StatementList :: // StatementList ::
// (StatementListItem)* <end_token> // (StatementListItem)* <end_token>
DCHECK_NOT_NULL(body); DCHECK_NOT_NULL(body);
...@@ -4517,10 +4499,9 @@ ParserBase<Impl>::ParseStatementList(StatementListT* body, ...@@ -4517,10 +4499,9 @@ ParserBase<Impl>::ParseStatementList(StatementListT* body,
} }
StatementT stat = ParseStatementListItem(); StatementT stat = ParseStatementListItem();
if (impl()->IsNull(stat)) return kLazyParsingComplete; if (impl()->IsNull(stat)) return;
body->Add(stat); body->Add(stat);
may_abort = false;
if (!impl()->IsStringLiteral(stat)) break; if (!impl()->IsStringLiteral(stat)) break;
...@@ -4534,7 +4515,7 @@ ParserBase<Impl>::ParseStatementList(StatementListT* body, ...@@ -4534,7 +4515,7 @@ ParserBase<Impl>::ParseStatementList(StatementListT* body,
impl()->ReportMessageAt(token_loc, impl()->ReportMessageAt(token_loc,
MessageTemplate::kIllegalLanguageModeDirective, MessageTemplate::kIllegalLanguageModeDirective,
"use strict"); "use strict");
return kLazyParsingComplete; return;
} }
} else if (use_asm) { } else if (use_asm) {
// Directive "use asm". // Directive "use asm".
...@@ -4551,28 +4532,12 @@ ParserBase<Impl>::ParseStatementList(StatementListT* body, ...@@ -4551,28 +4532,12 @@ ParserBase<Impl>::ParseStatementList(StatementListT* body,
// all scripts and functions get their own target stack thus avoiding illegal // all scripts and functions get their own target stack thus avoiding illegal
// breaks and continues across functions. // breaks and continues across functions.
TargetScopeT target_scope(this); TargetScopeT target_scope(this);
int count_statements = 0;
if (may_abort) {
while (peek() == Token::IDENTIFIER) {
StatementT stat = ParseStatementListItem();
// If we're allowed to abort, we will do so when we see a "long and
// trivial" function. Our current definition of "long and trivial" is:
// - over kLazyParseTrialLimit statements
// - all starting with an identifier (i.e., no if, for, while, etc.)
if (++count_statements > kLazyParseTrialLimit) return kLazyParsingAborted;
body->Add(stat);
}
}
while (peek() != end_token) { while (peek() != end_token) {
StatementT stat = ParseStatementListItem(); StatementT stat = ParseStatementListItem();
if (impl()->IsNull(stat)) return kLazyParsingComplete; if (impl()->IsNull(stat)) return;
if (stat->IsEmptyStatement()) continue; if (stat->IsEmptyStatement()) continue;
body->Add(stat); body->Add(stat);
} }
return kLazyParsingComplete;
} }
template <typename Impl> template <typename Impl>
......
...@@ -2585,8 +2585,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -2585,8 +2585,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
bool did_preparse_successfully = bool did_preparse_successfully =
should_preparse && should_preparse &&
SkipFunction(function_name, kind, function_type, scope, &num_parameters, SkipFunction(function_name, kind, function_type, scope, &num_parameters,
&produced_preparsed_scope_data, is_lazy_top_level_function, &produced_preparsed_scope_data);
&eager_compile_hint);
if (!did_preparse_successfully) { if (!did_preparse_successfully) {
// If skipping aborted, it rewound the scanner until before the LPAREN. // If skipping aborted, it rewound the scanner until before the LPAREN.
// Consume it in that case. // Consume it in that case.
...@@ -2658,8 +2657,7 @@ bool Parser::SkipFunction( ...@@ -2658,8 +2657,7 @@ bool Parser::SkipFunction(
const AstRawString* function_name, FunctionKind kind, const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters, DeclarationScope* function_scope, int* num_parameters,
ProducedPreParsedScopeData** produced_preparsed_scope_data, bool may_abort, ProducedPreParsedScopeData** produced_preparsed_scope_data) {
FunctionLiteral::EagerCompileHint* hint) {
FunctionState function_state(&function_state_, &scope_, function_scope); FunctionState function_state(&function_state_, &scope_, function_scope);
function_scope->set_zone(&preparser_zone_); function_scope->set_zone(&preparser_zone_);
...@@ -2706,16 +2704,8 @@ bool Parser::SkipFunction( ...@@ -2706,16 +2704,8 @@ bool Parser::SkipFunction(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse"); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse");
PreParser::PreParseResult result = reusable_preparser()->PreParseFunction( PreParser::PreParseResult result = reusable_preparser()->PreParseFunction(
function_name, kind, function_type, function_scope, may_abort, function_name, kind, function_type, function_scope, use_counts_,
use_counts_, produced_preparsed_scope_data, this->script_id()); produced_preparsed_scope_data, this->script_id());
// Return immediately if pre-parser decided to abort parsing.
if (result == PreParser::kPreParseAbort) {
bookmark.Apply();
function_scope->ResetAfterPreparsing(ast_value_factory(), true);
*hint = FunctionLiteral::kShouldEagerCompile;
return false;
}
if (result == PreParser::kPreParseStackOverflow) { if (result == PreParser::kPreParseStackOverflow) {
// Propagate stack overflow. // Propagate stack overflow.
......
...@@ -465,8 +465,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -465,8 +465,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// Skip over a lazy function, either using cached data if we have it, or // Skip over a lazy function, either using cached data if we have it, or
// by parsing the function with PreParser. Consumes the ending }. // by parsing the function with PreParser. Consumes the ending }.
// If may_abort == true, the (pre-)parser may decide to abort skipping
// in order to force the function to be eagerly parsed, after all.
// In case the preparser detects an error it cannot identify, it resets the // In case the preparser detects an error it cannot identify, it resets the
// scanner- and preparser state to the initial one, before PreParsing the // scanner- and preparser state to the initial one, before PreParsing the
// function. // function.
...@@ -477,8 +475,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -477,8 +475,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
bool SkipFunction(const AstRawString* function_name, FunctionKind kind, bool SkipFunction(const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters, DeclarationScope* function_scope, int* num_parameters,
ProducedPreParsedScopeData** produced_preparsed_scope_data, ProducedPreParsedScopeData** produced_preparsed_scope_data);
bool may_abort, FunctionLiteral::EagerCompileHint* hint);
Block* BuildParameterInitializationBlock( Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters); const ParserFormalParameters& parameters);
......
...@@ -107,7 +107,7 @@ void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const { ...@@ -107,7 +107,7 @@ void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const {
PreParser::PreParseResult PreParser::PreParseFunction( PreParser::PreParseResult PreParser::PreParseFunction(
const AstRawString* function_name, FunctionKind kind, const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, bool may_abort, int* use_counts, DeclarationScope* function_scope, int* use_counts,
ProducedPreParsedScopeData** produced_preparsed_scope_data, int script_id) { ProducedPreParsedScopeData** produced_preparsed_scope_data, int script_id) {
DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type()); DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
use_counts_ = use_counts; use_counts_ = use_counts;
...@@ -161,7 +161,6 @@ PreParser::PreParseResult PreParser::PreParseFunction( ...@@ -161,7 +161,6 @@ PreParser::PreParseResult PreParser::PreParseFunction(
Expect(Token::LBRACE); Expect(Token::LBRACE);
DeclarationScope* inner_scope = function_scope; DeclarationScope* inner_scope = function_scope;
LazyParsingResult result;
if (!formals.is_simple) { if (!formals.is_simple) {
inner_scope = NewVarblockScope(); inner_scope = NewVarblockScope();
...@@ -170,7 +169,7 @@ PreParser::PreParseResult PreParser::PreParseFunction( ...@@ -170,7 +169,7 @@ PreParser::PreParseResult PreParser::PreParseFunction(
{ {
BlockState block_state(&scope_, inner_scope); BlockState block_state(&scope_, inner_scope);
result = ParseStatementListAndLogFunction(&formals, may_abort); ParseStatementListAndLogFunction(&formals);
} }
bool allow_duplicate_parameters = false; bool allow_duplicate_parameters = false;
...@@ -205,12 +204,8 @@ PreParser::PreParseResult PreParser::PreParseFunction( ...@@ -205,12 +204,8 @@ PreParser::PreParseResult PreParser::PreParseFunction(
return kPreParseNotIdentifiableError; return kPreParseNotIdentifiableError;
} else if (has_error()) { } else if (has_error()) {
DCHECK(pending_error_handler()->has_pending_error()); DCHECK(pending_error_handler()->has_pending_error());
} else if (result == kLazyParsingAborted) {
DCHECK(!pending_error_handler()->has_error_unidentifiable_by_preparser());
return kPreParseAbort;
} else { } else {
DCHECK_EQ(Token::RBRACE, scanner()->peek()); DCHECK_EQ(Token::RBRACE, scanner()->peek());
DCHECK(result == kLazyParsingComplete);
if (!IsArrowFunction(kind)) { if (!IsArrowFunction(kind)) {
// Validate parameter names. We can do this only after parsing the // Validate parameter names. We can do this only after parsing the
...@@ -372,12 +367,10 @@ PreParser::Expression PreParser::ParseFunctionLiteral( ...@@ -372,12 +367,10 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
return Expression::Default(); return Expression::Default();
} }
PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction( void PreParser::ParseStatementListAndLogFunction(
PreParserFormalParameters* formals, bool may_abort) { PreParserFormalParameters* formals) {
PreParserScopedStatementList body(pointer_buffer()); PreParserScopedStatementList body(pointer_buffer());
LazyParsingResult result = ParseStatementList(&body, Token::RBRACE);
ParseStatementList(&body, Token::RBRACE, may_abort);
if (result == kLazyParsingAborted) return result;
// Position right after terminal '}'. // Position right after terminal '}'.
DCHECK_IMPLIES(!has_error(), scanner()->peek() == Token::RBRACE); DCHECK_IMPLIES(!has_error(), scanner()->peek() == Token::RBRACE);
...@@ -385,7 +378,6 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction( ...@@ -385,7 +378,6 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple); DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
log_.LogFunction(body_end, formals->num_parameters(), log_.LogFunction(body_end, formals->num_parameters(),
GetLastFunctionLiteralId()); GetLastFunctionLiteralId());
return kLazyParsingComplete;
} }
PreParserBlock PreParser::BuildParameterInitializationBlock( PreParserBlock PreParser::BuildParameterInitializationBlock(
......
...@@ -991,7 +991,6 @@ class PreParser : public ParserBase<PreParser> { ...@@ -991,7 +991,6 @@ class PreParser : public ParserBase<PreParser> {
enum PreParseResult { enum PreParseResult {
kPreParseStackOverflow, kPreParseStackOverflow,
kPreParseAbort,
kPreParseNotIdentifiableError, kPreParseNotIdentifiableError,
kPreParseSuccess kPreParseSuccess
}; };
...@@ -1030,7 +1029,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1030,7 +1029,7 @@ class PreParser : public ParserBase<PreParser> {
PreParseResult PreParseFunction( PreParseResult PreParseFunction(
const AstRawString* function_name, FunctionKind kind, const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, bool may_abort, int* use_counts, DeclarationScope* function_scope, int* use_counts,
ProducedPreParsedScopeData** produced_preparser_scope_data, ProducedPreParsedScopeData** produced_preparser_scope_data,
int script_id); int script_id);
...@@ -1069,8 +1068,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1069,8 +1068,7 @@ class PreParser : public ParserBase<PreParser> {
const AstRawString* name, FunctionKind kind, const AstRawString* name, FunctionKind kind,
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters, DeclarationScope* function_scope, int* num_parameters,
ProducedPreParsedScopeData** produced_preparsed_scope_data, ProducedPreParsedScopeData** produced_preparsed_scope_data) {
bool may_abort, FunctionLiteral::EagerCompileHint* hint) {
UNREACHABLE(); UNREACHABLE();
} }
...@@ -1085,8 +1083,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1085,8 +1083,7 @@ class PreParser : public ParserBase<PreParser> {
return literal; return literal;
} }
LazyParsingResult ParseStatementListAndLogFunction( void ParseStatementListAndLogFunction(PreParserFormalParameters* formals);
PreParserFormalParameters* formals, bool maybe_abort);
struct TemplateLiteralState {}; struct TemplateLiteralState {};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment