Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index 9c76e20a261ffa54d0246164990873373bc7b00b..43cc8127d223b51ef2c0882132168eae30e71ebb 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -2532,8 +2532,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
int pos = function_token_pos == kNoSourcePosition ? peek_position() |
: function_token_pos; |
- bool is_generator = IsGeneratorFunction(kind); |
- |
// Anonymous functions were passed either the empty symbol or a null |
// handle as the function name. Remember if we were passed a non-empty |
// handle to decide whether to invoke function name inference. |
@@ -2623,34 +2621,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
// This Scope lives in the main zone. We'll migrate data into that zone later. |
DeclarationScope* scope = NewFunctionScope(kind); |
SetLanguageMode(scope, language_mode); |
+#ifdef DEBUG |
+ scope->SetScopeName(function_name); |
+#endif |
ZoneList<Statement*>* body = nullptr; |
int materialized_literal_count = -1; |
int expected_property_count = -1; |
- DuplicateFinder duplicate_finder(scanner()->unicode_cache()); |
bool should_be_used_once_hint = false; |
- bool has_duplicate_parameters; |
- |
- FunctionState function_state(&function_state_, &scope_state_, scope); |
-#ifdef DEBUG |
- scope->SetScopeName(function_name); |
-#endif |
- |
- ExpressionClassifier formals_classifier(this, &duplicate_finder); |
- |
- if (is_generator) PrepareGeneratorVariables(&function_state); |
- |
- Expect(Token::LPAREN, CHECK_OK); |
- int start_position = scanner()->location().beg_pos; |
- this->scope()->set_start_position(start_position); |
- ParserFormalParameters formals(scope); |
- ParseFormalParameterList(&formals, CHECK_OK); |
- Expect(Token::RPAREN, CHECK_OK); |
- int formals_end_position = scanner()->location().end_pos; |
- |
- CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position, |
- formals_end_position, CHECK_OK); |
- Expect(Token::LBRACE, CHECK_OK); |
+ int num_parameters = -1; |
+ int function_length = -1; |
+ bool has_duplicate_parameters = false; |
{ |
// Temporary zones can nest. When we migrate free variables (see below), we |
@@ -2670,19 +2651,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
#endif |
// 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. |
+ // lazily. We'll call SkipLazyFunction, 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 || is_lazy_inner_function) { |
Scanner::BookmarkScope bookmark(scanner()); |
bookmark.Set(); |
- LazyParsingResult result = SkipLazyFunctionBody( |
- &materialized_literal_count, &expected_property_count, |
- is_lazy_inner_function, is_lazy_top_level_function, CHECK_OK); |
- |
- materialized_literal_count += formals.materialized_literals_count + |
- function_state.materialized_literal_count(); |
+ LazyParsingResult result = SkipLazyFunction( |
+ kind, scope, &num_parameters, &function_length, |
+ &has_duplicate_parameters, &materialized_literal_count, |
+ &expected_property_count, is_lazy_inner_function, |
+ is_lazy_top_level_function, CHECK_OK); |
if (result == kLazyParsingAborted) { |
DCHECK(is_lazy_top_level_function); |
@@ -2702,11 +2682,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
} |
if (!is_lazy_top_level_function && !is_lazy_inner_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(); |
+ body = ParseFunctionParametersAndBodyEagerly( |
+ function_name, pos, kind, function_type, scope, &num_parameters, |
+ &function_length, &has_duplicate_parameters, |
+ &materialized_literal_count, &expected_property_count, CHECK_OK); |
} |
DCHECK(use_temp_zone || !is_lazy_top_level_function); |
@@ -2726,17 +2705,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
function_name->byte_length(), function_name->raw_data()); |
} |
- // Parsing the body may change the language mode in our scope. |
+ // Validate function name. We can do this only after parsing the function, |
+ // since the function can declare itself strict. |
language_mode = scope->language_mode(); |
- |
- // Validate name and parameter names. We can do this only after parsing the |
- // function, since the function can declare itself strict. |
CheckFunctionName(language_mode, function_name, function_name_validity, |
function_name_location, CHECK_OK); |
- const bool allow_duplicate_parameters = |
- is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind); |
- ValidateFormalParameters(language_mode, allow_duplicate_parameters, |
- CHECK_OK); |
if (is_strict(language_mode)) { |
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(), |
@@ -2745,13 +2718,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
scope->end_position()); |
} |
CheckConflictingVarDeclarations(scope, CHECK_OK); |
- |
- if (body) { |
- // If body can be inspected, rewrite queued destructuring assignments |
- RewriteDestructuringAssignments(); |
- } |
- has_duplicate_parameters = |
- !classifier()->is_valid_formal_parameter_list_without_duplicates(); |
} // DiscardableZoneScope goes out of scope. |
FunctionLiteral::ParameterFlag duplicate_parameters = |
@@ -2761,9 +2727,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
// Note that the FunctionLiteral needs to be created in the main Zone again. |
FunctionLiteral* function_literal = factory()->NewFunctionLiteral( |
function_name, scope, body, materialized_literal_count, |
- expected_property_count, formals.num_parameters(), |
- formals.function_length, duplicate_parameters, function_type, |
- eager_compile_hint, pos); |
+ expected_property_count, num_parameters, function_length, |
+ duplicate_parameters, function_type, eager_compile_hint, pos); |
function_literal->set_function_token_position(function_token_pos); |
if (should_be_used_once_hint) |
function_literal->set_should_be_used_once_hint(); |
@@ -2775,35 +2740,50 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
return function_literal; |
} |
-Parser::LazyParsingResult Parser::SkipLazyFunctionBody( |
+Parser::LazyParsingResult Parser::SkipLazyFunction( |
+ FunctionKind kind, DeclarationScope* function_scope, int* num_parameters, |
+ int* function_length, bool* has_duplicate_parameters, |
int* materialized_literal_count, int* expected_property_count, |
bool is_inner_function, bool may_abort, bool* ok) { |
if (produce_cached_parse_data()) CHECK(log_); |
- int function_block_pos = position(); |
- DeclarationScope* scope = function_state_->scope(); |
- DCHECK(scope->is_function_scope()); |
+ // For normal functions, this is the position just before the left paren |
+ // (assuming the function is syntactically correct - however, it might not be, |
+ // so we cannot DCHECK for Token::LPAREN here). For arrow functions, this is |
+ // the position of the arrow. |
+ int cache_key_position = peek_position(); |
+ DCHECK_IMPLIES((kind & FunctionKind::kArrowFunction) != 0, |
+ scanner()->current_token() == Token::ARROW); |
+ |
// 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. |
+ // If we have cached data, we use it to skip parsing the function. The data |
+ // contains the information we need to construct the lazy function. |
FunctionEntry entry = |
- cached_parse_data_->GetFunctionEntry(function_block_pos); |
+ cached_parse_data_->GetFunctionEntry(cache_key_position); |
// Check that cached data is valid. If not, mark it as invalid (the embedder |
// handles it). Note that end position greater than end of stream is safe, |
// and hard to check. |
- if (entry.is_valid() && entry.end_pos() > function_block_pos) { |
+ if (entry.is_valid() && entry.end_pos() > cache_key_position) { |
scanner()->SeekForward(entry.end_pos() - 1); |
- |
- scope->set_end_position(entry.end_pos()); |
+ // We need the start position separately from the cache key, since for |
+ // arrow functions, the scope start position is at the lparen of the |
+ // parameter list, and we've already read past it. |
+ function_scope->set_start_position(entry.start_pos()); |
+ function_scope->set_end_position(entry.end_pos()); |
Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); |
- total_preparse_skipped_ += scope->end_position() - function_block_pos; |
+ total_preparse_skipped_ += |
+ function_scope->end_position() - function_scope->start_position(); |
+ *num_parameters = entry.num_parameters(); |
+ *function_length = entry.function_length(); |
+ *has_duplicate_parameters = entry.has_duplicate_parameters(); |
*materialized_literal_count = entry.literal_count(); |
*expected_property_count = entry.property_count(); |
- SetLanguageMode(scope, entry.language_mode()); |
- if (entry.uses_super_property()) scope->RecordSuperPropertyUsage(); |
- if (entry.calls_eval()) scope->RecordEvalCall(); |
+ SetLanguageMode(function_scope, entry.language_mode()); |
+ if (entry.uses_super_property()) |
+ function_scope->RecordSuperPropertyUsage(); |
+ if (entry.calls_eval()) function_scope->RecordEvalCall(); |
return kLazyParsingComplete; |
} |
cached_parse_data_->Reject(); |
@@ -2811,8 +2791,8 @@ Parser::LazyParsingResult Parser::SkipLazyFunctionBody( |
// With no cached data, we partially parse the function, without building an |
// AST. This gathers the data needed to build a lazy function. |
SingletonLogger logger; |
- PreParser::PreParseResult result = |
- ParseFunctionBodyWithPreParser(&logger, is_inner_function, may_abort); |
+ PreParser::PreParseResult result = ParseFunctionWithPreParser( |
+ kind, function_scope, &logger, is_inner_function, may_abort); |
// Return immediately if pre-parser decided to abort parsing. |
if (result == PreParser::kPreParseAbort) return kLazyParsingAborted; |
@@ -2829,21 +2809,27 @@ Parser::LazyParsingResult Parser::SkipLazyFunctionBody( |
*ok = false; |
return kLazyParsingComplete; |
} |
- scope->set_end_position(logger.end()); |
+ DCHECK_NE(kNoSourcePosition, function_scope->start_position()); |
+ function_scope->set_end_position(logger.end()); |
Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); |
- total_preparse_skipped_ += scope->end_position() - function_block_pos; |
+ total_preparse_skipped_ += |
+ function_scope->end_position() - function_scope->start_position(); |
+ *num_parameters = logger.num_parameters(); |
+ *function_length = logger.function_length(); |
+ *has_duplicate_parameters = logger.has_duplicate_parameters(); |
*materialized_literal_count = logger.literals(); |
*expected_property_count = logger.properties(); |
- SetLanguageMode(scope, logger.language_mode()); |
- if (logger.uses_super_property()) scope->RecordSuperPropertyUsage(); |
- if (logger.calls_eval()) scope->RecordEvalCall(); |
+ SetLanguageMode(function_scope, logger.language_mode()); |
+ if (logger.uses_super_property()) function_scope->RecordSuperPropertyUsage(); |
+ if (logger.calls_eval()) function_scope->RecordEvalCall(); |
if (!is_inner_function && produce_cached_parse_data()) { |
DCHECK(log_); |
- // Position right after terminal '}'. |
- int body_end = scanner()->location().end_pos; |
- log_->LogFunction(function_block_pos, body_end, *materialized_literal_count, |
- *expected_property_count, language_mode(), |
- scope->uses_super_property(), scope->calls_eval()); |
+ log_->LogFunction(cache_key_position, function_scope->start_position(), |
+ function_scope->end_position(), *num_parameters, |
+ *function_length, *has_duplicate_parameters, |
+ *materialized_literal_count, *expected_property_count, |
+ language_mode(), function_scope->uses_super_property(), |
+ function_scope->calls_eval()); |
} |
return kLazyParsingComplete; |
} |
@@ -3116,6 +3102,54 @@ Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) { |
Yield::kOnExceptionThrow); |
} |
+ZoneList<Statement*>* Parser::ParseFunctionParametersAndBodyEagerly( |
+ const AstRawString* function_name, int pos, FunctionKind kind, |
+ FunctionLiteral::FunctionType function_type, |
+ DeclarationScope* function_scope, int* num_parameters, int* function_length, |
+ bool* has_duplicate_parameters, int* materialized_literal_count, |
+ int* expected_property_count, bool* ok) { |
+ FunctionState function_state(&function_state_, &scope_state_, function_scope); |
+ |
+ DuplicateFinder duplicate_finder(scanner()->unicode_cache()); |
+ ExpressionClassifier formals_classifier(this, &duplicate_finder); |
+ |
+ if (IsGeneratorFunction(kind)) PrepareGeneratorVariables(&function_state); |
+ |
+ Expect(Token::LPAREN, CHECK_OK); |
+ int start_position = scanner()->location().beg_pos; |
+ function_scope->set_start_position(start_position); |
+ ParserFormalParameters formals(function_scope); |
+ ParseFormalParameterList(&formals, CHECK_OK); |
+ Expect(Token::RPAREN, CHECK_OK); |
+ int formals_end_position = scanner()->location().end_pos; |
+ *num_parameters = formals.num_parameters(); |
+ *function_length = formals.function_length; |
+ |
+ CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position, |
+ formals_end_position, CHECK_OK); |
+ Expect(Token::LBRACE, CHECK_OK); |
+ |
+ ZoneList<Statement*>* body = ParseEagerFunctionBody( |
+ function_name, pos, formals, kind, function_type, ok); |
+ |
+ // Validate parameter names. We can do this only after parsing the function, |
+ // since the function can declare itself strict. |
+ const bool allow_duplicate_parameters = |
+ is_sloppy(function_scope->language_mode()) && formals.is_simple && |
+ !IsConciseMethod(kind); |
+ ValidateFormalParameters(function_scope->language_mode(), |
+ allow_duplicate_parameters, CHECK_OK); |
+ |
+ RewriteDestructuringAssignments(); |
+ |
+ *has_duplicate_parameters = |
+ !classifier()->is_valid_formal_parameter_list_without_duplicates(); |
+ |
+ *materialized_literal_count = function_state.materialized_literal_count(); |
+ *expected_property_count = function_state.expected_property_count(); |
+ return body; |
+} |
+ |
ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
const AstRawString* function_name, int pos, |
const ParserFormalParameters& parameters, FunctionKind kind, |
@@ -3272,7 +3306,8 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
return result; |
} |
-PreParser::PreParseResult Parser::ParseFunctionBodyWithPreParser( |
+PreParser::PreParseResult Parser::ParseFunctionWithPreParser( |
+ FunctionKind kind, DeclarationScope* function_scope, |
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. |
@@ -3281,8 +3316,6 @@ PreParser::PreParseResult Parser::ParseFunctionBodyWithPreParser( |
} |
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse"); |
- DCHECK_EQ(Token::LBRACE, scanner()->current_token()); |
- |
if (reusable_preparser_ == NULL) { |
reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(), |
NULL, stack_limit_); |
@@ -3301,10 +3334,9 @@ PreParser::PreParseResult Parser::ParseFunctionBodyWithPreParser( |
// state; we don't parse inner functions in the abortable mode anyway. |
DCHECK(!is_inner_function || !may_abort); |
- DeclarationScope* function_scope = function_state_->scope(); |
PreParser::PreParseResult result = reusable_preparser_->PreParseFunction( |
- function_scope, parsing_module_, logger, is_inner_function, may_abort, |
- use_counts_); |
+ kind, function_scope, parsing_module_, logger, is_inner_function, |
+ may_abort, use_counts_); |
if (pre_parse_timer_ != NULL) { |
pre_parse_timer_->Stop(); |
} |