Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index 1e0932fe5fe6980cf516076e74b20fe0ad187aae..77173a40d70d4da11112647817391631715776ee 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -122,17 +122,11 @@ |
if (use_temp_zone) { |
parser_->fni_ = &fni_; |
parser_->zone_ = temp_zone; |
- if (parser_->reusable_preparser_ != nullptr) { |
- parser_->reusable_preparser_->zone_ = temp_zone; |
- } |
} |
} |
~DiscardableZoneScope() { |
parser_->fni_ = prev_fni_; |
parser_->zone_ = prev_zone_; |
- if (parser_->reusable_preparser_ != nullptr) { |
- parser_->reusable_preparser_->zone_ = prev_zone_; |
- } |
} |
private: |
@@ -3000,9 +2994,7 @@ |
// These are all things we can know at this point, without looking at the |
// function itself. |
- // We separate between lazy parsing top level functions and lazy parsing inner |
- // functions, because the latter needs to do more work. In particular, we need |
- // to track unresolved variables to distinguish between these cases: |
+ // In addition, we need to distinguish between these cases: |
// (function foo() { |
// bar = function() { return 1; } |
// })(); |
@@ -3014,19 +3006,17 @@ |
// Now foo will be parsed eagerly and compiled eagerly (optimization: assume |
// parenthesis before the function means that it will be called |
- // immediately). bar can be parsed lazily, but we need to parse it in a mode |
- // that tracks unresolved variables. |
- DCHECK_IMPLIES(mode() == PARSE_LAZILY, FLAG_lazy); |
- DCHECK_IMPLIES(mode() == PARSE_LAZILY, allow_lazy()); |
- DCHECK_IMPLIES(mode() == PARSE_LAZILY, !allow_natives()); |
- DCHECK_IMPLIES(mode() == PARSE_LAZILY, extension_ == nullptr); |
- |
- bool is_lazy_top_level_function = |
- mode() == PARSE_LAZILY && |
- eager_compile_hint == FunctionLiteral::kShouldLazyCompile && |
- scope()->AllowsLazyParsingWithoutUnresolvedVariables(); |
- |
- // Determine whether we can still do the inner function lazy parsing. |
+ // immediately). The inner function *must* be parsed eagerly to resolve the |
+ // possible reference to the variable in foo's scope. However, it's possible |
+ // that it will be compiled lazily. |
+ |
+ // To make this additional case work, both Parser and PreParser implement a |
+ // logic where only top-level functions will be parsed lazily. |
+ bool is_lazily_parsed = mode() == PARSE_LAZILY && |
+ scope()->AllowsLazyParsing() && |
+ !function_state_->next_function_is_parenthesized(); |
+ |
+ // Determine whether the function body can be discarded after parsing. |
// The preconditions are: |
// - Lazy compilation has to be enabled. |
// - Neither V8 natives nor native function declarations can be allowed, |
@@ -3041,19 +3031,15 @@ |
// - The function literal shouldn't be hinted to eagerly compile. |
// - For asm.js functions the body needs to be available when module |
// validation is active, because we examine the entire module at once. |
- |
- // Inner functions will be parsed by using a temporary Zone. After parsing, we |
- // will migrate unresolved variable into a Scope in the main Zone. |
- // TODO(marja): Refactor parsing modes: simplify this. |
- bool is_lazy_inner_function = |
- !is_lazy_top_level_function && FLAG_lazy && !allow_natives() && |
+ bool use_temp_zone = |
+ !is_lazily_parsed && FLAG_lazy && !allow_natives() && |
extension_ == NULL && allow_lazy() && |
function_type == FunctionLiteral::kDeclaration && |
eager_compile_hint != FunctionLiteral::kShouldEagerCompile && |
!(FLAG_validate_asm && scope()->IsAsmModule()); |
DeclarationScope* main_scope = nullptr; |
- if (is_lazy_inner_function) { |
+ if (use_temp_zone) { |
// This Scope lives in the main Zone; we'll migrate data into it later. |
main_scope = NewFunctionScope(kind); |
} |
@@ -3078,11 +3064,11 @@ |
// to do scope analysis correctly after full parsing, we migrate needed |
// information from scope into main_scope when the function has been parsed. |
Zone temp_zone(zone()->allocator()); |
- DiscardableZoneScope zone_scope(this, &temp_zone, is_lazy_inner_function); |
+ DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone); |
DeclarationScope* scope = NewFunctionScope(kind); |
SetLanguageMode(scope, language_mode); |
- if (!is_lazy_inner_function) { |
+ if (!use_temp_zone) { |
main_scope = scope; |
} else { |
DCHECK(main_scope->zone() != scope->zone()); |
@@ -3126,17 +3112,18 @@ |
// which says whether we need to create an arguments adaptor frame). |
if (formals.has_rest) arity--; |
- // Eager or lazy parse? If is_lazy_top_level_function, we'll parse |
- // lazily. We'll call SkipLazyFunctionBody, which may decide to abort lazy |
- // parsing if it suspects that wasn't a good idea. If so (in which case the |
- // parser is expected to have backtracked), or if we didn't try to lazy |
- // parse in the first place, we'll have to parse eagerly. |
- if (is_lazy_top_level_function) { |
+ // Eager or lazy parse? |
+ // If is_lazily_parsed, we'll parse lazily. We'll call SkipLazyFunctionBody, |
+ // which may decide to abort lazy parsing if it suspects that wasn't a good |
+ // idea. If so (in which case the parser is expected to have backtracked), |
+ // or if we didn't try to lazy parse in the first place, we'll have to parse |
+ // eagerly. |
+ if (is_lazily_parsed) { |
Scanner::BookmarkScope bookmark(scanner()); |
bool may_abort = bookmark.Set(); |
- LazyParsingResult result = SkipLazyFunctionBody( |
- &materialized_literal_count, &expected_property_count, false, |
- may_abort, CHECK_OK); |
+ LazyParsingResult result = |
+ SkipLazyFunctionBody(&materialized_literal_count, |
+ &expected_property_count, may_abort, CHECK_OK); |
materialized_literal_count += formals.materialized_literals_count + |
function_state.materialized_literal_count(); |
@@ -3144,7 +3131,7 @@ |
if (result == kLazyParsingAborted) { |
bookmark.Reset(); |
// Trigger eager (re-)parsing, just below this block. |
- is_lazy_top_level_function = false; |
+ is_lazily_parsed = false; |
// This is probably an initialization function. Inform the compiler it |
// should also eager-compile this function, and that we expect it to be |
@@ -3153,29 +3140,17 @@ |
should_be_used_once_hint = true; |
} |
} |
- if (is_lazy_inner_function) { |
- if (FLAG_lazy_inner_functions) { |
- LazyParsingResult result = SkipLazyFunctionBody( |
- &materialized_literal_count, &expected_property_count, true, false, |
- CHECK_OK); |
- materialized_literal_count += |
- formals.materialized_literals_count + |
- function_state.materialized_literal_count(); |
- DCHECK(result != kLazyParsingAborted); |
- USE(result); |
- } else { |
- ParseEagerFunctionBody(function_name, pos, formals, kind, function_type, |
- CHECK_OK); |
- materialized_literal_count = |
- function_state.materialized_literal_count(); |
- expected_property_count = function_state.expected_property_count(); |
- } |
- } else if (!is_lazy_top_level_function) { |
+ if (!is_lazily_parsed) { |
body = ParseEagerFunctionBody(function_name, pos, formals, kind, |
function_type, CHECK_OK); |
materialized_literal_count = function_state.materialized_literal_count(); |
expected_property_count = function_state.expected_property_count(); |
+ if (use_temp_zone) { |
+ // If the preconditions are correct the function body should never be |
+ // accessed, but do this anyway for better behaviour if they're wrong. |
+ body = nullptr; |
+ } |
} |
// Parsing the body may change the language mode in our scope. |
@@ -3209,7 +3184,7 @@ |
has_duplicate_parameters = |
!classifier()->is_valid_formal_parameter_list_without_duplicates(); |
- if (is_lazy_inner_function) { |
+ if (use_temp_zone) { |
DCHECK(main_scope != scope); |
scope->AnalyzePartially(main_scope, &previous_zone_ast_node_factory); |
} |
@@ -3263,15 +3238,13 @@ |
Parser::LazyParsingResult Parser::SkipLazyFunctionBody( |
int* materialized_literal_count, int* expected_property_count, |
- bool is_inner_function, bool may_abort, bool* ok) { |
+ bool may_abort, bool* ok) { |
if (produce_cached_parse_data()) CHECK(log_); |
int function_block_pos = position(); |
DeclarationScope* scope = this->scope()->AsDeclarationScope(); |
DCHECK(scope->is_function_scope()); |
- // Inner functions are not part of the cached data. |
- if (!is_inner_function && consume_cached_parse_data() && |
- !cached_parse_data_->rejected()) { |
+ if (consume_cached_parse_data() && !cached_parse_data_->rejected()) { |
// If we have cached data, we use it to skip parsing the function body. The |
// data contains the information we need to construct the lazy function. |
FunctionEntry entry = |
@@ -3298,7 +3271,7 @@ |
// AST. This gathers the data needed to build a lazy function. |
SingletonLogger logger; |
PreParser::PreParseResult result = |
- ParseLazyFunctionBodyWithPreParser(&logger, is_inner_function, may_abort); |
+ ParseLazyFunctionBodyWithPreParser(&logger, may_abort); |
// Return immediately if pre-parser decided to abort parsing. |
if (result == PreParser::kPreParseAbort) { |
return kLazyParsingAborted; |
@@ -3324,7 +3297,7 @@ |
SetLanguageMode(scope, logger.language_mode()); |
if (logger.uses_super_property()) scope->RecordSuperPropertyUsage(); |
if (logger.calls_eval()) scope->RecordEvalCall(); |
- if (!is_inner_function && produce_cached_parse_data()) { |
+ if (produce_cached_parse_data()) { |
DCHECK(log_); |
// Position right after terminal '}'. |
int body_end = scanner()->location().end_pos; |
@@ -3626,12 +3599,11 @@ |
const AstRawString* function_name, int pos, |
const ParserFormalParameters& parameters, FunctionKind kind, |
FunctionLiteral::FunctionType function_type, bool* ok) { |
- // Everything inside an eagerly parsed function will be parsed eagerly (see |
- // comment above). Lazy inner functions are handled separately and they won't |
- // require the mode to be PARSE_LAZILY (see ParseFunctionLiteral). |
- // TODO(marja): Refactor parsing modes: remove this. |
+ // Everything inside an eagerly parsed function will be parsed eagerly |
+ // (see comment above). |
ParsingModeScope parsing_mode(this, PARSE_EAGERLY); |
ZoneList<Statement*>* result = new(zone()) ZoneList<Statement*>(8, zone()); |
+ |
static const int kFunctionNameAssignmentIndex = 0; |
if (function_type == FunctionLiteral::kNamedExpression) { |
DCHECK(function_name != NULL); |
@@ -3787,7 +3759,7 @@ |
} |
PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( |
- SingletonLogger* logger, bool is_inner_function, bool may_abort) { |
+ SingletonLogger* logger, bool may_abort) { |
// This function may be called on a background thread too; record only the |
// main thread preparse times. |
if (pre_parse_timer_ != NULL) { |
@@ -3812,36 +3784,10 @@ |
SET_ALLOW(harmony_class_fields); |
#undef SET_ALLOW |
} |
- // Aborting inner function preparsing would leave scopes in an inconsistent |
- // state; we don't parse inner functions in the abortable mode anyway. |
- DCHECK(!is_inner_function || !may_abort); |
- |
- FunctionKind kind = function_state_->kind(); |
- PreParser::PreParseResult result; |
- if (!is_inner_function) { |
- // If we don't need to look at the scope, construct a dummy scope chain |
- // which is not connected to the real scope chain. |
- LanguageMode mode = language_mode(); |
- bool has_simple_parameters = |
- scope()->AsDeclarationScope()->has_simple_parameters(); |
- DeclarationScope* top_scope = NewScriptScope(); |
- top_scope->SetLanguageMode(mode); |
- FunctionState top_state(&function_state_, &scope_state_, top_scope, |
- kNormalFunction); |
- DeclarationScope* function_scope = NewFunctionScope(kind); |
- if (!has_simple_parameters) { |
- function_scope->SetHasNonSimpleParameters(); |
- } |
- result = reusable_preparser_->PreParseLazyFunction( |
- kind, function_scope, parsing_module_, logger, is_inner_function, |
- may_abort, use_counts_); |
- } else { |
- // Detaching the scopes created by PreParser from the Scope chain must be |
- // done above (see ParseFunctionLiteral & AnalyzePartially). |
- result = reusable_preparser_->PreParseLazyFunction( |
- kind, scope()->AsDeclarationScope(), parsing_module_, logger, |
- is_inner_function, may_abort, use_counts_); |
- } |
+ PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( |
+ language_mode(), function_state_->kind(), |
+ scope()->AsDeclarationScope()->has_simple_parameters(), parsing_module_, |
+ logger, may_abort, use_counts_); |
if (pre_parse_timer_ != NULL) { |
pre_parse_timer_->Stop(); |
} |