| Index: src/parsing/parser.cc
 | 
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
 | 
| index 77173a40d70d4da11112647817391631715776ee..1e0932fe5fe6980cf516076e74b20fe0ad187aae 100644
 | 
| --- a/src/parsing/parser.cc
 | 
| +++ b/src/parsing/parser.cc
 | 
| @@ -122,11 +122,17 @@ class DiscardableZoneScope {
 | 
|      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:
 | 
| @@ -2994,7 +3000,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|    // These are all things we can know at this point, without looking at the
 | 
|    // function itself.
 | 
|  
 | 
| -  // In addition, we need to distinguish between these cases:
 | 
| +  // 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:
 | 
|    // (function foo() {
 | 
|    //   bar = function() { return 1; }
 | 
|    //  })();
 | 
| @@ -3006,17 +3014,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|  
 | 
|    // Now foo will be parsed eagerly and compiled eagerly (optimization: assume
 | 
|    // parenthesis before the function means that it will be called
 | 
| -  // 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.
 | 
| +  // 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.
 | 
|    // The preconditions are:
 | 
|    // - Lazy compilation has to be enabled.
 | 
|    // - Neither V8 natives nor native function declarations can be allowed,
 | 
| @@ -3031,15 +3041,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|    // - 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.
 | 
| -  bool use_temp_zone =
 | 
| -      !is_lazily_parsed && FLAG_lazy && !allow_natives() &&
 | 
| +
 | 
| +  // 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() &&
 | 
|        extension_ == NULL && allow_lazy() &&
 | 
|        function_type == FunctionLiteral::kDeclaration &&
 | 
|        eager_compile_hint != FunctionLiteral::kShouldEagerCompile &&
 | 
|        !(FLAG_validate_asm && scope()->IsAsmModule());
 | 
|  
 | 
|    DeclarationScope* main_scope = nullptr;
 | 
| -  if (use_temp_zone) {
 | 
| +  if (is_lazy_inner_function) {
 | 
|      // This Scope lives in the main Zone; we'll migrate data into it later.
 | 
|      main_scope = NewFunctionScope(kind);
 | 
|    }
 | 
| @@ -3064,11 +3078,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|      // 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, use_temp_zone);
 | 
| +    DiscardableZoneScope zone_scope(this, &temp_zone, is_lazy_inner_function);
 | 
|  
 | 
|      DeclarationScope* scope = NewFunctionScope(kind);
 | 
|      SetLanguageMode(scope, language_mode);
 | 
| -    if (!use_temp_zone) {
 | 
| +    if (!is_lazy_inner_function) {
 | 
|        main_scope = scope;
 | 
|      } else {
 | 
|        DCHECK(main_scope->zone() != scope->zone());
 | 
| @@ -3112,18 +3126,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|      // which says whether we need to create an arguments adaptor frame).
 | 
|      if (formals.has_rest) arity--;
 | 
|  
 | 
| -    // 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) {
 | 
| +    // 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) {
 | 
|        Scanner::BookmarkScope bookmark(scanner());
 | 
|        bool may_abort = bookmark.Set();
 | 
| -      LazyParsingResult result =
 | 
| -          SkipLazyFunctionBody(&materialized_literal_count,
 | 
| -                               &expected_property_count, may_abort, CHECK_OK);
 | 
| +      LazyParsingResult result = SkipLazyFunctionBody(
 | 
| +          &materialized_literal_count, &expected_property_count, false,
 | 
| +          may_abort, CHECK_OK);
 | 
|  
 | 
|        materialized_literal_count += formals.materialized_literals_count +
 | 
|                                      function_state.materialized_literal_count();
 | 
| @@ -3131,7 +3144,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|        if (result == kLazyParsingAborted) {
 | 
|          bookmark.Reset();
 | 
|          // Trigger eager (re-)parsing, just below this block.
 | 
| -        is_lazily_parsed = false;
 | 
| +        is_lazy_top_level_function = false;
 | 
|  
 | 
|          // This is probably an initialization function. Inform the compiler it
 | 
|          // should also eager-compile this function, and that we expect it to be
 | 
| @@ -3140,17 +3153,29 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|          should_be_used_once_hint = true;
 | 
|        }
 | 
|      }
 | 
| -    if (!is_lazily_parsed) {
 | 
| +    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) {
 | 
|        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.
 | 
| @@ -3184,7 +3209,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
 | 
|      has_duplicate_parameters =
 | 
|          !classifier()->is_valid_formal_parameter_list_without_duplicates();
 | 
|  
 | 
| -    if (use_temp_zone) {
 | 
| +    if (is_lazy_inner_function) {
 | 
|        DCHECK(main_scope != scope);
 | 
|        scope->AnalyzePartially(main_scope, &previous_zone_ast_node_factory);
 | 
|      }
 | 
| @@ -3238,13 +3263,15 @@ Expression* Parser::ParseAsyncFunctionExpression(bool* ok) {
 | 
|  
 | 
|  Parser::LazyParsingResult Parser::SkipLazyFunctionBody(
 | 
|      int* materialized_literal_count, int* expected_property_count,
 | 
| -    bool may_abort, bool* ok) {
 | 
| +    bool is_inner_function, 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());
 | 
| -  if (consume_cached_parse_data() && !cached_parse_data_->rejected()) {
 | 
| +  // Inner functions are not part of the cached data.
 | 
| +  if (!is_inner_function && 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 =
 | 
| @@ -3271,7 +3298,7 @@ Parser::LazyParsingResult Parser::SkipLazyFunctionBody(
 | 
|    // AST. This gathers the data needed to build a lazy function.
 | 
|    SingletonLogger logger;
 | 
|    PreParser::PreParseResult result =
 | 
| -      ParseLazyFunctionBodyWithPreParser(&logger, may_abort);
 | 
| +      ParseLazyFunctionBodyWithPreParser(&logger, is_inner_function, may_abort);
 | 
|    // Return immediately if pre-parser decided to abort parsing.
 | 
|    if (result == PreParser::kPreParseAbort) {
 | 
|      return kLazyParsingAborted;
 | 
| @@ -3297,7 +3324,7 @@ Parser::LazyParsingResult Parser::SkipLazyFunctionBody(
 | 
|    SetLanguageMode(scope, logger.language_mode());
 | 
|    if (logger.uses_super_property()) scope->RecordSuperPropertyUsage();
 | 
|    if (logger.calls_eval()) scope->RecordEvalCall();
 | 
| -  if (produce_cached_parse_data()) {
 | 
| +  if (!is_inner_function && produce_cached_parse_data()) {
 | 
|      DCHECK(log_);
 | 
|      // Position right after terminal '}'.
 | 
|      int body_end = scanner()->location().end_pos;
 | 
| @@ -3599,11 +3626,12 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
 | 
|      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).
 | 
| +  // 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.
 | 
|    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);
 | 
| @@ -3759,7 +3787,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
 | 
|  }
 | 
|  
 | 
|  PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
 | 
| -    SingletonLogger* logger, bool may_abort) {
 | 
| +    SingletonLogger* logger, bool is_inner_function, 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) {
 | 
| @@ -3784,10 +3812,36 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
 | 
|      SET_ALLOW(harmony_class_fields);
 | 
|  #undef SET_ALLOW
 | 
|    }
 | 
| -  PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
 | 
| -      language_mode(), function_state_->kind(),
 | 
| -      scope()->AsDeclarationScope()->has_simple_parameters(), parsing_module_,
 | 
| -      logger, may_abort, use_counts_);
 | 
| +  // 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_);
 | 
| +  }
 | 
|    if (pre_parse_timer_ != NULL) {
 | 
|      pre_parse_timer_->Stop();
 | 
|    }
 | 
| 
 |