| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 409059778a6a5f44606f6d0bed20af710cb797ec..54e57d5096618cb21485a12e5ace3401b25d06b2 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -3973,8 +3973,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| scope_->DeclareFunctionVar(fvar_declaration);
|
| }
|
|
|
| - // Determine whether the function will be lazily compiled.
|
| - // The heuristics are:
|
| + // Determine if the function can be parsed lazily. Lazy parsing is different
|
| + // from lazy compilation; we need to parse more eagerly than we compile.
|
| +
|
| + // We can only parse lazily if we also compile lazily. The heuristics for
|
| + // lazy compilation are:
|
| // - It must not have been prohibited by the caller to Parse (some callers
|
| // need a full AST).
|
| // - The outer scope must allow lazy compilation of inner functions.
|
| @@ -3984,12 +3987,31 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| // compiled.
|
| // These are all things we can know at this point, without looking at the
|
| // function itself.
|
| - bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
|
| - scope_->AllowsLazyCompilation() &&
|
| - !parenthesized_function_);
|
| +
|
| + // In addition, we need to distinguish between these cases:
|
| + // (function foo() {
|
| + // bar = function() { return 1; }
|
| + // })();
|
| + // and
|
| + // (function foo() {
|
| + // var a = 1;
|
| + // bar = function() { return a; }
|
| + // })();
|
| +
|
| + // 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_->AllowsLazyCompilation() &&
|
| + !parenthesized_function_);
|
| parenthesized_function_ = false; // The bit was set for this function only.
|
|
|
| - if (is_lazily_compiled) {
|
| + if (is_lazily_parsed) {
|
| int function_block_pos = position();
|
| FunctionEntry entry;
|
| if (pre_parse_data_ != NULL) {
|
| @@ -4013,7 +4035,20 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| expected_property_count = entry.property_count();
|
| scope_->SetLanguageMode(entry.language_mode());
|
| } else {
|
| - is_lazily_compiled = false;
|
| + // This case happens when we have preparse data but it doesn't contain
|
| + // an entry for the function. As a safety net, fall back to eager
|
| + // parsing. It is unclear whether PreParser's laziness analysis can
|
| + // produce different results than the Parser's laziness analysis (see
|
| + // https://codereview.chromium.org/7565003 ). This safety net is
|
| + // guarding against the case where Parser thinks a function should be
|
| + // lazily parsed, but PreParser thinks it should be eagerly parsed --
|
| + // in that case we fall back to eager parsing in Parser, too. Note
|
| + // that the opposite case is worse: if PreParser thinks a function
|
| + // should be lazily parsed, but Parser thinks it should be eagerly
|
| + // parsed, it will never advance the preparse data beyond that
|
| + // function and all further laziness will fail (all functions will be
|
| + // parsed eagerly).
|
| + is_lazily_parsed = false;
|
| }
|
| } else {
|
| // With no preparser data, we partially parse the function, without
|
| @@ -4050,7 +4085,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| }
|
| }
|
|
|
| - if (!is_lazily_compiled) {
|
| + if (!is_lazily_parsed) {
|
| + // Everything inside an eagerly parsed function will be parsed eagerly
|
| + // (see comment above).
|
| ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
| body = new(zone()) ZoneList<Statement*>(8, zone());
|
| if (fvar != NULL) {
|
|
|