| Index: src/preparser.cc
|
| diff --git a/src/preparser.cc b/src/preparser.cc
|
| index 987900a20d5844ebfef3e17d93fcd4c43f9503ea..e0c0ffd883d27255e4b83be25f6cbdb1b1b22f92 100644
|
| --- a/src/preparser.cc
|
| +++ b/src/preparser.cc
|
| @@ -11,6 +11,7 @@
|
| #include "src/globals.h"
|
| #include "src/hashmap.h"
|
| #include "src/list.h"
|
| +#include "src/parser.h"
|
| #include "src/preparse-data.h"
|
| #include "src/preparse-data-format.h"
|
| #include "src/preparser.h"
|
| @@ -20,6 +21,74 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| +PreParserScope::~PreParserScope() {
|
| + if (unbound_variables_ && outer_scope_) {
|
| + for (ZoneHashMap::Entry* p = unbound_variables_->Start(); p != NULL;
|
| + p = unbound_variables_->Next(p)) {
|
| + AstRawString* identifier = static_cast<AstRawString*>(p->key);
|
| + if (!declared_variables_->Lookup(identifier, identifier->hash(), false,
|
| + ZoneAllocationPolicy(zone_))) {
|
| + outer_scope_->RecordVariableUsage(identifier);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +PreParserScope* PreParserScope::DeclarationScope() {
|
| + PreParserScope* scope = this;
|
| + while (!scope->is_declaration_scope()) {
|
| + scope = scope->outer_scope();
|
| + }
|
| + return scope;
|
| +}
|
| +
|
| +
|
| +void PreParserScope::RecordVariableUsage(const AstRawString* identifier) {
|
| + ZoneAllocationPolicy allocator(zone_);
|
| + if (!declared_variables_->Lookup(const_cast<AstRawString*>(identifier),
|
| + identifier->hash(), false, allocator)) {
|
| + unbound_variables_->Lookup(const_cast<AstRawString*>(identifier),
|
| + identifier->hash(), true, allocator);
|
| + }
|
| +}
|
| +
|
| +
|
| +void PreParserScope::LogUnboundVariables(ParserRecorder* recorder) {
|
| + for (ZoneHashMap::Entry* p = unbound_variables_->Start(); p != NULL;
|
| + p = unbound_variables_->Next(p)) {
|
| + AstRawString* identifier = static_cast<AstRawString*>(p->key);
|
| + if (!declared_variables_->Lookup(identifier, identifier->hash(), false,
|
| + ZoneAllocationPolicy(zone_))) {
|
| + recorder->LogIdentifier(identifier);
|
| + }
|
| + }
|
| + unbound_variables_->Clear();
|
| +}
|
| +
|
| +
|
| +void PreParserScope::Declare(const AstRawString* identifier, bool lexical) {
|
| + if (lexical || is_declaration_scope()) {
|
| + DCHECK(declared_variables_);
|
| + declared_variables_->Lookup(const_cast<AstRawString*>(identifier),
|
| + identifier->hash(), true,
|
| + ZoneAllocationPolicy(zone_));
|
| + } else {
|
| + DeclarationScope()->Declare(identifier, lexical);
|
| + }
|
| +}
|
| +
|
| +
|
| +void PreParserTraits::RecordCurrentSymbolAsIdentifierExpression() {
|
| + if (pre_parser_->log_ != NULL && pre_parser_->log_identifiers_) {
|
| + DCHECK(pre_parser_->ast_value_factory_ != NULL);
|
| + const AstRawString* identifier =
|
| + pre_parser_->scanner()->CurrentSymbol(pre_parser_->ast_value_factory_);
|
| + pre_parser_->scope_->RecordVariableUsage(identifier);
|
| + }
|
| +}
|
| +
|
| +
|
| void PreParserTraits::ReportMessageAt(Scanner::Location location,
|
| const char* message,
|
| const char* arg,
|
| @@ -42,6 +111,15 @@ void PreParserTraits::ReportMessageAt(int start_pos,
|
| }
|
|
|
|
|
| +void PreParserTraits::CheckPossibleEvalCall(PreParserExpression expression,
|
| + PreParserScope* scope) {
|
| + if (pre_parser_->log_ != NULL && pre_parser_->log_identifiers_ &&
|
| + expression.IsIdentifier() && expression.AsIdentifier().IsEval()) {
|
| + pre_parser_->log_->LogEvalCall();
|
| + }
|
| +}
|
| +
|
| +
|
| PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
|
| if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) {
|
| return PreParserIdentifier::FutureReserved();
|
| @@ -100,14 +178,16 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral(
|
|
|
|
|
| PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
| - StrictMode strict_mode, bool is_generator, ParserRecorder* log) {
|
| + StrictMode strict_mode, bool is_generator, bool log_identifiers,
|
| + ParserRecorder* log) {
|
| + log_identifiers_ = log_identifiers;
|
| log_ = log;
|
| // Lazy functions always have trivial outer scopes (no with/catch scopes).
|
| - PreParserScope top_scope(scope_, GLOBAL_SCOPE);
|
| + PreParserScope top_scope = NewScope(NULL, GLOBAL_SCOPE);
|
| PreParserFactory top_factory(NULL);
|
| FunctionState top_state(&function_state_, &scope_, &top_scope, &top_factory);
|
| scope_->SetStrictMode(strict_mode);
|
| - PreParserScope function_scope(scope_, FUNCTION_SCOPE);
|
| + PreParserScope function_scope = NewScope(scope_, FUNCTION_SCOPE);
|
| PreParserFactory function_factory(NULL);
|
| FunctionState function_state(&function_state_, &scope_, &function_scope,
|
| &function_factory);
|
| @@ -329,6 +409,12 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
|
| bool is_strict_reserved = false;
|
| Identifier name = ParseIdentifierOrStrictReservedWord(
|
| &is_strict_reserved, CHECK_OK);
|
| + if (log_identifiers_) {
|
| + DCHECK(ast_value_factory_);
|
| + const AstRawString* identifier =
|
| + scanner()->CurrentSymbol(ast_value_factory_);
|
| + scope_->Declare(identifier);
|
| + }
|
| ParseFunctionLiteral(name, scanner()->location(), is_strict_reserved,
|
| is_generator ? FunctionKind::kGeneratorFunction
|
| : FunctionKind::kNormalFunction,
|
| @@ -344,6 +430,12 @@ PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
|
| bool is_strict_reserved = false;
|
| Identifier name =
|
| ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
|
| + if (log_identifiers_) {
|
| + DCHECK(ast_value_factory_);
|
| + const AstRawString* identifier =
|
| + scanner()->CurrentSymbol(ast_value_factory_);
|
| + scope_->Declare(identifier);
|
| + }
|
| ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos,
|
| CHECK_OK);
|
| return Statement::Default();
|
| @@ -358,10 +450,14 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
|
| // (ECMA-262, 3rd, 12.2)
|
| //
|
| Expect(Token::LBRACE, CHECK_OK);
|
| - while (peek() != Token::RBRACE) {
|
| - if (allow_harmony_scoping() && strict_mode() == STRICT) {
|
| + if (allow_harmony_scoping() && strict_mode() == STRICT) {
|
| + PreParserScope block_scope = NewScope(scope_, BLOCK_SCOPE);
|
| + BlockState block_state(&scope_, &block_scope);
|
| + while (peek() != Token::RBRACE) {
|
| ParseSourceElement(CHECK_OK);
|
| - } else {
|
| + }
|
| + } else {
|
| + while (peek() != Token::RBRACE) {
|
| ParseStatement(CHECK_OK);
|
| }
|
| }
|
| @@ -409,6 +505,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
| // ConstBinding ::
|
| // BindingPattern '=' AssignmentExpression
|
| bool require_initializer = false;
|
| + bool lexical = false;
|
| if (peek() == Token::VAR) {
|
| Consume(Token::VAR);
|
| } else if (peek() == Token::CONST) {
|
| @@ -431,6 +528,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
| return Statement::Default();
|
| }
|
| require_initializer = true;
|
| + lexical = true;
|
| } else {
|
| Scanner::Location location = scanner()->peek_location();
|
| ReportMessageAt(location, "strict_const");
|
| @@ -445,6 +543,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| + lexical = true;
|
| } else {
|
| *ok = false;
|
| return Statement::Default();
|
| @@ -459,6 +558,12 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
| // Parse variable name.
|
| if (nvars > 0) Consume(Token::COMMA);
|
| ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
|
| + if (log_identifiers_) {
|
| + DCHECK(ast_value_factory_);
|
| + const AstRawString* identifier =
|
| + scanner()->CurrentSymbol(ast_value_factory_);
|
| + scope_->Declare(identifier, lexical);
|
| + }
|
| nvars++;
|
| if (peek() == Token::ASSIGN || require_initializer) {
|
| Expect(Token::ASSIGN, CHECK_OK);
|
| @@ -593,7 +698,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
|
| ParseExpression(true, CHECK_OK);
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| - PreParserScope with_scope(scope_, WITH_SCOPE);
|
| + PreParserScope with_scope = NewScope(scope_, WITH_SCOPE);
|
| BlockState block_state(&scope_, &with_scope);
|
| ParseStatement(CHECK_OK);
|
| return Statement::Default();
|
| @@ -673,6 +778,11 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
| // ForStatement ::
|
| // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
|
|
|
| + // Create an in-between scope for let-bound iteration variables.
|
| + PreParserScope* saved_scope = scope_;
|
| + PreParserScope for_scope = NewScope(scope_, BLOCK_SCOPE);
|
| + scope_ = &for_scope;
|
| +
|
| Expect(Token::FOR, CHECK_OK);
|
| Expect(Token::LPAREN, CHECK_OK);
|
| if (peek() != Token::SEMICOLON) {
|
| @@ -687,10 +797,14 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
| bool accept_IN = decl_count == 1 && !(is_let && has_initializers);
|
| bool accept_OF = !has_initializers;
|
| if (accept_IN && CheckInOrOf(accept_OF)) {
|
| + // The expression does not see the loop variable.
|
| + scope_ = saved_scope;
|
| ParseExpression(true, CHECK_OK);
|
| + scope_ = &for_scope;
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| ParseStatement(CHECK_OK);
|
| + scope_ = saved_scope;
|
| return Statement::Default();
|
| }
|
| } else {
|
| @@ -700,6 +814,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| ParseStatement(CHECK_OK);
|
| + scope_ = saved_scope;
|
| return Statement::Default();
|
| }
|
| }
|
| @@ -719,6 +834,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| ParseStatement(ok);
|
| + scope_ = saved_scope;
|
| return Statement::Default();
|
| }
|
|
|
| @@ -765,9 +881,15 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
|
| Consume(Token::CATCH);
|
| Expect(Token::LPAREN, CHECK_OK);
|
| ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
|
| + if (log_identifiers_) {
|
| + DCHECK(ast_value_factory_);
|
| + const AstRawString* identifier =
|
| + scanner()->CurrentSymbol(ast_value_factory_);
|
| + scope_->Declare(identifier);
|
| + }
|
| Expect(Token::RPAREN, CHECK_OK);
|
| {
|
| - PreParserScope with_scope(scope_, WITH_SCOPE);
|
| + PreParserScope with_scope = NewScope(scope_, WITH_SCOPE);
|
| BlockState block_state(&scope_, &with_scope);
|
| ParseBlock(CHECK_OK);
|
| }
|
| @@ -812,7 +934,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
|
|
| // Parse function body.
|
| ScopeType outer_scope_type = scope_->type();
|
| - PreParserScope function_scope(scope_, FUNCTION_SCOPE);
|
| + PreParserScope function_scope = NewScope(scope_, FUNCTION_SCOPE);
|
| PreParserFactory factory(NULL);
|
| FunctionState function_state(&function_state_, &scope_, &function_scope,
|
| &factory);
|
| @@ -836,6 +958,12 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
| bool is_strict_reserved = false;
|
| Identifier param_name =
|
| ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
|
| + if (log_identifiers_) {
|
| + DCHECK(ast_value_factory_);
|
| + const AstRawString* identifier =
|
| + scanner()->CurrentSymbol(ast_value_factory_);
|
| + scope_->Declare(identifier);
|
| + }
|
| if (!eval_args_error_loc.IsValid() && param_name.IsEvalOrArguments()) {
|
| eval_args_error_loc = scanner()->location();
|
| }
|
| @@ -915,6 +1043,9 @@ void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
|
| // Position right after terminal '}'.
|
| DCHECK_EQ(Token::RBRACE, scanner()->peek());
|
| int body_end = scanner()->peek_location().end_pos;
|
| + if (log_identifiers_) {
|
| + scope_->LogUnboundVariables(log_);
|
| + }
|
| log_->LogFunction(body_start, body_end,
|
| function_state_->materialized_literal_count(),
|
| function_state_->expected_property_count(),
|
|
|