Commit e1341ca8 authored by marja's avatar marja Committed by Commit bot

Preparse inner functions.

This is an overly pessimistic approach where PreParser only keeps
track of unresolved variables, but doesn't declare anything. This
will result in context-allocating variables in the outer function
unnecessarily, if the variable names clash with variable names
used by the inner function (even if the variables are not the
same). However, we have been unable to prove that this approach
wouldn't be good enough for the practical purposes.

Review-Url: https://codereview.chromium.org/2322243002
Cr-Commit-Position: refs/heads/master@{#39469}
parent 347931e6
...@@ -1045,12 +1045,14 @@ void DeclarationScope::AllocateVariables(ParseInfo* info, AnalyzeMode mode) { ...@@ -1045,12 +1045,14 @@ void DeclarationScope::AllocateVariables(ParseInfo* info, AnalyzeMode mode) {
AllocateScopeInfosRecursively(info->isolate(), mode, outer_scope); AllocateScopeInfosRecursively(info->isolate(), mode, outer_scope);
} }
bool Scope::AllowsLazyParsing() const { bool Scope::AllowsLazyParsingWithoutUnresolvedVariables() const {
// If we are inside a block scope, we must parse eagerly to find out how // If we are inside a block scope, we must find unresolved variables in the
// to allocate variables on the block scope. At this point, declarations may // inner scopes to find out how to allocate variables on the block scope. At
// not have yet been parsed. // this point, declarations may not have yet been parsed.
for (const Scope* s = this; s != nullptr; s = s->outer_scope_) { for (const Scope* s = this; s != nullptr; s = s->outer_scope_) {
if (s->is_block_scope()) return false; if (s->is_block_scope()) return false;
// TODO(marja): Refactor parsing modes: also add s->is_function_scope()
// here.
} }
return true; return true;
} }
......
...@@ -342,8 +342,9 @@ class Scope: public ZoneObject { ...@@ -342,8 +342,9 @@ class Scope: public ZoneObject {
int StackLocalCount() const; int StackLocalCount() const;
int ContextLocalCount() const; int ContextLocalCount() const;
// Determine if we can parse a function literal in this scope lazily. // Determine if we can parse a function literal in this scope lazily without
bool AllowsLazyParsing() const; // caring about the unresolved variables within.
bool AllowsLazyParsingWithoutUnresolvedVariables() const;
// The number of contexts between this and scope; zero if this == scope. // The number of contexts between this and scope; zero if this == scope.
int ContextChainLength(Scope* scope) const; int ContextChainLength(Scope* scope) const;
......
...@@ -831,6 +831,7 @@ DEFINE_BOOL(trace_maps, false, "trace map creation") ...@@ -831,6 +831,7 @@ DEFINE_BOOL(trace_maps, false, "trace map creation")
// parser.cc // parser.cc
DEFINE_BOOL(allow_natives_syntax, false, "allow natives syntax") DEFINE_BOOL(allow_natives_syntax, false, "allow natives syntax")
DEFINE_BOOL(trace_parse, false, "trace parsing and preparsing") DEFINE_BOOL(trace_parse, false, "trace parsing and preparsing")
DEFINE_BOOL(lazy_inner_functions, true, "enable lazy parsing inner functions")
// simulator-arm.cc, simulator-arm64.cc and simulator-mips.cc // simulator-arm.cc, simulator-arm64.cc and simulator-mips.cc
DEFINE_BOOL(trace_sim, false, "Trace simulator execution") DEFINE_BOOL(trace_sim, false, "Trace simulator execution")
......
...@@ -3889,14 +3889,17 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( ...@@ -3889,14 +3889,17 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// Multiple statement body // Multiple statement body
Consume(Token::LBRACE); Consume(Token::LBRACE);
DCHECK_EQ(scope(), formal_parameters.scope); DCHECK_EQ(scope(), formal_parameters.scope);
bool is_lazily_parsed = (mode() == PARSE_LAZILY && bool is_lazily_parsed =
formal_parameters.scope->AllowsLazyParsing()); (mode() == PARSE_LAZILY &&
formal_parameters.scope
->AllowsLazyParsingWithoutUnresolvedVariables());
// TODO(marja): consider lazy-parsing inner arrow functions too.
if (is_lazily_parsed) { if (is_lazily_parsed) {
Scanner::BookmarkScope bookmark(scanner()); Scanner::BookmarkScope bookmark(scanner());
bool may_abort = bookmark.Set(); bool may_abort = bookmark.Set();
LazyParsingResult result = impl()->SkipLazyFunctionBody( LazyParsingResult result = impl()->SkipLazyFunctionBody(
&materialized_literal_count, &expected_property_count, may_abort, &materialized_literal_count, &expected_property_count, false,
CHECK_OK); may_abort, CHECK_OK);
if (formal_parameters.materialized_literals_count > 0) { if (formal_parameters.materialized_literals_count > 0) {
materialized_literal_count += materialized_literal_count +=
......
This diff is collapsed.
...@@ -481,10 +481,11 @@ class Parser : public ParserBase<Parser> { ...@@ -481,10 +481,11 @@ class Parser : public ParserBase<Parser> {
// in order to force the function to be eagerly parsed, after all. // in order to force the function to be eagerly parsed, after all.
LazyParsingResult SkipLazyFunctionBody(int* materialized_literal_count, LazyParsingResult SkipLazyFunctionBody(int* materialized_literal_count,
int* expected_property_count, int* expected_property_count,
bool may_abort, bool* ok); bool is_inner_function, bool may_abort,
bool* ok);
PreParser::PreParseResult ParseLazyFunctionBodyWithPreParser( PreParser::PreParseResult ParseLazyFunctionBodyWithPreParser(
SingletonLogger* logger, bool may_abort); SingletonLogger* logger, bool is_inner_function, bool may_abort);
Block* BuildParameterInitializationBlock( Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok); const ParserFormalParameters& parameters, bool* ok);
...@@ -1066,6 +1067,7 @@ class Parser : public ParserBase<Parser> { ...@@ -1066,6 +1067,7 @@ class Parser : public ParserBase<Parser> {
} }
// Parser's private field members. // Parser's private field members.
friend class DiscardableZoneScope; // Uses reusable_preparser_.
Scanner scanner_; Scanner scanner_;
PreParser* reusable_preparser_; PreParser* reusable_preparser_;
......
...@@ -38,8 +38,10 @@ namespace internal { ...@@ -38,8 +38,10 @@ namespace internal {
#define CHECK_OK CHECK_OK_VALUE(Statement::Default()) #define CHECK_OK CHECK_OK_VALUE(Statement::Default())
#define CHECK_OK_VOID CHECK_OK_VALUE(this->Void()) #define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
PreParserIdentifier PreParser::GetSymbol() const { namespace {
switch (scanner()->current_token()) {
PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
switch (scanner->current_token()) {
case Token::ENUM: case Token::ENUM:
return PreParserIdentifier::Enum(); return PreParserIdentifier::Enum();
case Token::AWAIT: case Token::AWAIT:
...@@ -55,34 +57,46 @@ PreParserIdentifier PreParser::GetSymbol() const { ...@@ -55,34 +57,46 @@ PreParserIdentifier PreParser::GetSymbol() const {
case Token::ASYNC: case Token::ASYNC:
return PreParserIdentifier::Async(); return PreParserIdentifier::Async();
default: default:
if (scanner()->UnescapedLiteralMatches("eval", 4)) if (scanner->UnescapedLiteralMatches("eval", 4))
return PreParserIdentifier::Eval(); return PreParserIdentifier::Eval();
if (scanner()->UnescapedLiteralMatches("arguments", 9)) if (scanner->UnescapedLiteralMatches("arguments", 9))
return PreParserIdentifier::Arguments(); return PreParserIdentifier::Arguments();
if (scanner()->UnescapedLiteralMatches("undefined", 9)) if (scanner->UnescapedLiteralMatches("undefined", 9))
return PreParserIdentifier::Undefined(); return PreParserIdentifier::Undefined();
if (scanner()->LiteralMatches("prototype", 9)) if (scanner->LiteralMatches("prototype", 9))
return PreParserIdentifier::Prototype(); return PreParserIdentifier::Prototype();
if (scanner()->LiteralMatches("constructor", 11)) if (scanner->LiteralMatches("constructor", 11))
return PreParserIdentifier::Constructor(); return PreParserIdentifier::Constructor();
return PreParserIdentifier::Default(); return PreParserIdentifier::Default();
} }
} }
} // unnamed namespace
PreParserIdentifier PreParser::GetSymbol() const {
PreParserIdentifier symbol = GetSymbolHelper(scanner());
if (track_unresolved_variables_) {
const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
DCHECK_NOT_NULL(result);
symbol.string_ = result;
}
return symbol;
}
PreParser::PreParseResult PreParser::PreParseLazyFunction( PreParser::PreParseResult PreParser::PreParseLazyFunction(
LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters, FunctionKind kind, DeclarationScope* function_scope, bool parsing_module,
bool parsing_module, ParserRecorder* log, bool may_abort, int* use_counts) { ParserRecorder* log, bool is_inner_function, bool may_abort,
int* use_counts) {
parsing_module_ = parsing_module; parsing_module_ = parsing_module;
log_ = log; log_ = log;
use_counts_ = use_counts; use_counts_ = use_counts;
// Lazy functions always have trivial outer scopes (no with/catch scopes). DCHECK(!track_unresolved_variables_);
track_unresolved_variables_ = is_inner_function;
// The caller passes the function_scope which is not yet inserted into the
// scope_state_. All scopes above the function_scope are ignored by the
// PreParser.
DCHECK_NULL(scope_state_); DCHECK_NULL(scope_state_);
DeclarationScope* top_scope = NewScriptScope();
FunctionState top_state(&function_state_, &scope_state_, top_scope,
kNormalFunction);
scope()->SetLanguageMode(language_mode);
DeclarationScope* function_scope = NewFunctionScope(kind);
if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters();
FunctionState function_state(&function_state_, &scope_state_, function_scope, FunctionState function_state(&function_state_, &scope_state_, function_scope,
kind); kind);
DCHECK_EQ(Token::LBRACE, scanner()->current_token()); DCHECK_EQ(Token::LBRACE, scanner()->current_token());
...@@ -90,6 +104,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction( ...@@ -90,6 +104,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
int start_position = peek_position(); int start_position = peek_position();
LazyParsingResult result = ParseLazyFunctionLiteralBody(may_abort, &ok); LazyParsingResult result = ParseLazyFunctionLiteralBody(may_abort, &ok);
use_counts_ = nullptr; use_counts_ = nullptr;
track_unresolved_variables_ = false;
if (result == kLazyParsingAborted) { if (result == kLazyParsingAborted) {
return kPreParseAbort; return kPreParseAbort;
} else if (stack_overflow()) { } else if (stack_overflow()) {
...@@ -474,6 +489,21 @@ void PreParser::ParseAsyncArrowSingleExpressionBody(PreParserStatementList body, ...@@ -474,6 +489,21 @@ void PreParser::ParseAsyncArrowSingleExpressionBody(PreParserStatementList body,
body->Add(PreParserStatement::ExpressionStatement(return_value), zone()); body->Add(PreParserStatement::ExpressionStatement(return_value), zone());
} }
PreParserExpression PreParser::ExpressionFromIdentifier(
PreParserIdentifier name, int start_position, int end_position,
InferName infer) {
if (track_unresolved_variables_) {
AstNodeFactory factory(ast_value_factory());
// Setting the Zone is necessary because zone_ might be the temp Zone, and
// AstValueFactory doesn't know about it.
factory.set_zone(zone());
DCHECK_NOT_NULL(name.string_);
scope()->NewUnresolved(&factory, name.string_, start_position, end_position,
NORMAL_VARIABLE);
}
return PreParserExpression::FromIdentifier(name);
}
#undef CHECK_OK #undef CHECK_OK
#undef CHECK_OK_CUSTOM #undef CHECK_OK_CUSTOM
......
...@@ -112,10 +112,12 @@ class PreParserIdentifier { ...@@ -112,10 +112,12 @@ class PreParserIdentifier {
kAsyncIdentifier kAsyncIdentifier
}; };
explicit PreParserIdentifier(Type type) : type_(type) {} explicit PreParserIdentifier(Type type) : type_(type), string_(nullptr) {}
Type type_; Type type_;
// Only non-nullptr when PreParser.track_unresolved_variables_ is true.
const AstRawString* string_;
friend class PreParserExpression; friend class PreParserExpression;
friend class PreParser;
}; };
...@@ -761,7 +763,8 @@ class PreParser : public ParserBase<PreParser> { ...@@ -761,7 +763,8 @@ class PreParser : public ParserBase<PreParser> {
ParserRecorder* log, uintptr_t stack_limit) ParserRecorder* log, uintptr_t stack_limit)
: ParserBase<PreParser>(zone, scanner, stack_limit, NULL, : ParserBase<PreParser>(zone, scanner, stack_limit, NULL,
ast_value_factory, log), ast_value_factory, log),
use_counts_(nullptr) {} use_counts_(nullptr),
track_unresolved_variables_(false) {}
// Pre-parse the program from the character stream; returns true on // Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully // success (even if parsing failed, the pre-parse data successfully
...@@ -807,10 +810,10 @@ class PreParser : public ParserBase<PreParser> { ...@@ -807,10 +810,10 @@ class PreParser : public ParserBase<PreParser> {
// keyword and parameters, and have consumed the initial '{'. // keyword and parameters, and have consumed the initial '{'.
// At return, unless an error occurred, the scanner is positioned before the // At return, unless an error occurred, the scanner is positioned before the
// the final '}'. // the final '}'.
PreParseResult PreParseLazyFunction(LanguageMode language_mode, PreParseResult PreParseLazyFunction(FunctionKind kind,
FunctionKind kind, DeclarationScope* function_scope,
bool has_simple_parameters,
bool parsing_module, ParserRecorder* log, bool parsing_module, ParserRecorder* log,
bool track_unresolved_variables,
bool may_abort, int* use_counts); bool may_abort, int* use_counts);
private: private:
...@@ -838,9 +841,9 @@ class PreParser : public ParserBase<PreParser> { ...@@ -838,9 +841,9 @@ class PreParser : public ParserBase<PreParser> {
const PreParserFormalParameters& parameters, FunctionKind kind, const PreParserFormalParameters& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok); FunctionLiteral::FunctionType function_type, bool* ok);
V8_INLINE LazyParsingResult V8_INLINE LazyParsingResult SkipLazyFunctionBody(
SkipLazyFunctionBody(int* materialized_literal_count, int* materialized_literal_count, int* expected_property_count,
int* expected_property_count, bool may_abort, bool* ok) { bool track_unresolved_variables, bool may_abort, bool* ok) {
UNREACHABLE(); UNREACHABLE();
return kLazyParsingComplete; return kLazyParsingComplete;
} }
...@@ -1260,11 +1263,9 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1260,11 +1263,9 @@ class PreParser : public ParserBase<PreParser> {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
V8_INLINE PreParserExpression ExpressionFromIdentifier( PreParserExpression ExpressionFromIdentifier(
PreParserIdentifier name, int start_position, int end_position, PreParserIdentifier name, int start_position, int end_position,
InferName infer = InferName::kYes) { InferName infer = InferName::kYes);
return PreParserExpression::FromIdentifier(name);
}
V8_INLINE PreParserExpression ExpressionFromString(int pos) { V8_INLINE PreParserExpression ExpressionFromString(int pos) {
if (scanner()->UnescapedLiteralMatches("use strict", 10)) { if (scanner()->UnescapedLiteralMatches("use strict", 10)) {
...@@ -1379,6 +1380,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1379,6 +1380,7 @@ class PreParser : public ParserBase<PreParser> {
// Preparser's private field members. // Preparser's private field members.
int* use_counts_; int* use_counts_;
bool track_unresolved_variables_;
}; };
PreParserExpression PreParser::SpreadCall(PreParserExpression function, PreParserExpression PreParser::SpreadCall(PreParserExpression function,
......
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