From ec18b79fac932038a2c0e45a69fc6d865c48f1bd Mon Sep 17 00:00:00 2001 From: "marja@chromium.org" Date: Wed, 19 Feb 2014 14:50:33 +0000 Subject: [PATCH] Add comments about lazy parsing and lazy compilation. Also rename is_lazily_compiled in (Pre)Parser; it really means "is lazily parsed" and doesn't correspond to the lazy compilation decision. R=svenpanne@chromium.org BUG= Review URL: https://codereview.chromium.org/169223009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19492 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/parser.cc | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- src/preparser.cc | 13 ++++++------- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 0fa5816..902fcac 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -3930,8 +3930,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. @@ -3941,12 +3944,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) { @@ -3970,7 +3992,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 @@ -4007,7 +4042,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(8, zone()); if (fvar != NULL) { diff --git a/src/preparser.cc b/src/preparser.cc index 934a2e5..e96c8cd 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -1284,16 +1284,15 @@ PreParser::Expression PreParser::ParseFunctionLiteral( } Expect(Token::RPAREN, CHECK_OK); - // Determine if the function will be lazily compiled. - // Currently only happens to top-level functions. - // Optimistically assume that all top-level functions are lazily compiled. - bool is_lazily_compiled = (outer_scope_type == GLOBAL_SCOPE && - !inside_with && allow_lazy() && - !parenthesized_function_); + // See Parser::ParseFunctionLiteral for more information about lazy parsing + // and lazy compilation. + bool is_lazily_parsed = (outer_scope_type == GLOBAL_SCOPE && + !inside_with && allow_lazy() && + !parenthesized_function_); parenthesized_function_ = false; Expect(Token::LBRACE, CHECK_OK); - if (is_lazily_compiled) { + if (is_lazily_parsed) { ParseLazyFunctionLiteralBody(CHECK_OK); } else { ParseSourceElements(Token::RBRACE, ok); -- 2.7.4