| 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();
|
| }
|
|
|