| Index: src/ast/scopes.cc
|
| diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc
|
| index 9209c2bb417d8614a1ca727971ec3e24c19ed8c0..8be4d1722a86b5fe78766d046f7bbac329ce89d3 100644
|
| --- a/src/ast/scopes.cc
|
| +++ b/src/ast/scopes.cc
|
| @@ -20,6 +20,14 @@ namespace internal {
|
|
|
| namespace {
|
| void* kDummyPreParserVariable = reinterpret_cast<void*>(0x1);
|
| +void* kDummyPreParserLexicalVariable = reinterpret_cast<void*>(0x2);
|
| +
|
| +bool IsLexical(Variable* variable) {
|
| + if (variable == kDummyPreParserLexicalVariable) return true;
|
| + if (variable == kDummyPreParserVariable) return false;
|
| + return IsLexicalVariableMode(variable->mode());
|
| +}
|
| +
|
| } // namespace
|
|
|
| // ----------------------------------------------------------------------------
|
| @@ -56,14 +64,16 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope,
|
| return reinterpret_cast<Variable*>(p->value);
|
| }
|
|
|
| -void VariableMap::DeclareName(Zone* zone, const AstRawString* name) {
|
| +void VariableMap::DeclareName(Zone* zone, const AstRawString* name,
|
| + VariableMode mode) {
|
| Entry* p =
|
| ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
|
| ZoneAllocationPolicy(zone));
|
| if (p->value == nullptr) {
|
| // The variable has not been declared yet -> insert it.
|
| DCHECK_EQ(name, p->key);
|
| - p->value = kDummyPreParserVariable;
|
| + p->value =
|
| + mode == VAR ? kDummyPreParserVariable : kDummyPreParserLexicalVariable;
|
| }
|
| }
|
|
|
| @@ -92,21 +102,27 @@ Variable* VariableMap::Lookup(const AstRawString* name) {
|
| return NULL;
|
| }
|
|
|
| +void SloppyBlockFunctionMap::Delegate::set_statement(Statement* statement) {
|
| + if (statement_ != nullptr) {
|
| + statement_->set_statement(statement);
|
| + }
|
| +}
|
| +
|
| SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone)
|
| : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {}
|
|
|
| -void SloppyBlockFunctionMap::Declare(Zone* zone, const AstRawString* name,
|
| - SloppyBlockFunctionStatement* stmt) {
|
| +void SloppyBlockFunctionMap::Declare(
|
| + Zone* zone, const AstRawString* name,
|
| + SloppyBlockFunctionMap::Delegate* delegate) {
|
| // AstRawStrings are unambiguous, i.e., the same string is always represented
|
| // by the same AstRawString*.
|
| Entry* p =
|
| ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
|
| ZoneAllocationPolicy(zone));
|
| - stmt->set_next(static_cast<SloppyBlockFunctionStatement*>(p->value));
|
| - p->value = stmt;
|
| + delegate->set_next(static_cast<SloppyBlockFunctionMap::Delegate*>(p->value));
|
| + p->value = delegate;
|
| }
|
|
|
| -
|
| // ----------------------------------------------------------------------------
|
| // Implementation of Scope
|
|
|
| @@ -448,11 +464,21 @@ int Scope::num_parameters() const {
|
| return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0;
|
| }
|
|
|
| +void DeclarationScope::DeclareSloppyBlockFunction(
|
| + const AstRawString* name, Scope* scope,
|
| + SloppyBlockFunctionStatement* statement) {
|
| + auto* delegate =
|
| + new (zone()) SloppyBlockFunctionMap::Delegate(scope, statement);
|
| + sloppy_block_function_map_.Declare(zone(), name, delegate);
|
| +}
|
| +
|
| void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
|
| DCHECK(is_sloppy(language_mode()));
|
| DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() ||
|
| (is_block_scope() && outer_scope()->is_function_scope()));
|
| - DCHECK(HasSimpleParameters() || is_block_scope());
|
| + DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_);
|
| + DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_);
|
| +
|
| bool has_simple_parameters = HasSimpleParameters();
|
| // For each variable which is used as a function declaration in a sloppy
|
| // block,
|
| @@ -484,7 +510,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
|
| bool var_created = false;
|
|
|
| // Write in assignments to var for each block-scoped function declaration
|
| - auto delegates = static_cast<SloppyBlockFunctionStatement*>(p->value);
|
| + auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value);
|
|
|
| DeclarationScope* decl_scope = this;
|
| while (decl_scope->is_eval_scope()) {
|
| @@ -492,7 +518,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
|
| }
|
| Scope* outer_scope = decl_scope->outer_scope();
|
|
|
| - for (SloppyBlockFunctionStatement* delegate = delegates;
|
| + for (SloppyBlockFunctionMap::Delegate* delegate = delegates;
|
| delegate != nullptr; delegate = delegate->next()) {
|
| // Check if there's a conflict with a lexical declaration
|
| Scope* query_scope = delegate->scope()->outer_scope();
|
| @@ -506,7 +532,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
|
| // `{ let e; try {} catch (e) { function e(){} } }`
|
| do {
|
| var = query_scope->LookupLocal(name);
|
| - if (var != nullptr && IsLexicalVariableMode(var->mode())) {
|
| + if (var != nullptr && IsLexical(var)) {
|
| should_hoist = false;
|
| break;
|
| }
|
| @@ -518,25 +544,32 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
|
| // Declare a var-style binding for the function in the outer scope
|
| if (!var_created) {
|
| var_created = true;
|
| - VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE);
|
| - Declaration* declaration =
|
| - factory->NewVariableDeclaration(proxy, this, kNoSourcePosition);
|
| - // Based on the preceding check, it doesn't matter what we pass as
|
| - // allow_harmony_restrictive_generators and
|
| - // sloppy_mode_block_scope_function_redefinition.
|
| - bool ok = true;
|
| - DeclareVariable(declaration, VAR,
|
| - Variable::DefaultInitializationFlag(VAR), false,
|
| - nullptr, &ok);
|
| - CHECK(ok); // Based on the preceding check, this should not fail
|
| + if (factory) {
|
| + VariableProxy* proxy =
|
| + factory->NewVariableProxy(name, NORMAL_VARIABLE);
|
| + auto declaration =
|
| + factory->NewVariableDeclaration(proxy, this, kNoSourcePosition);
|
| + // Based on the preceding check, it doesn't matter what we pass as
|
| + // allow_harmony_restrictive_generators and
|
| + // sloppy_mode_block_scope_function_redefinition.
|
| + bool ok = true;
|
| + DeclareVariable(declaration, VAR,
|
| + Variable::DefaultInitializationFlag(VAR), false,
|
| + nullptr, &ok);
|
| + CHECK(ok); // Based on the preceding check, this should not fail
|
| + } else {
|
| + DeclareVariableName(name, VAR);
|
| + }
|
| }
|
|
|
| - Expression* assignment = factory->NewAssignment(
|
| - Token::ASSIGN, NewUnresolved(factory, name),
|
| - delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
|
| - Statement* statement =
|
| - factory->NewExpressionStatement(assignment, kNoSourcePosition);
|
| - delegate->set_statement(statement);
|
| + if (factory) {
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, NewUnresolved(factory, name),
|
| + delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
|
| + Statement* statement =
|
| + factory->NewExpressionStatement(assignment, kNoSourcePosition);
|
| + delegate->set_statement(statement);
|
| + }
|
| }
|
| }
|
| }
|
| @@ -1048,7 +1081,7 @@ void Scope::DeclareVariableName(const AstRawString* name, VariableMode mode) {
|
| DCHECK(scope_info_.is_null());
|
|
|
| // Declare the variable in the declaration scope.
|
| - variables_.DeclareName(zone(), name);
|
| + variables_.DeclareName(zone(), name, mode);
|
| }
|
|
|
| VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory,
|
| @@ -1647,7 +1680,7 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, Scope* outer_scope_end) {
|
| if (var == nullptr) return var;
|
|
|
| // TODO(marja): Separate LookupRecursive for preparsed scopes better.
|
| - if (var == kDummyPreParserVariable) {
|
| + if (var == kDummyPreParserVariable || var == kDummyPreParserLexicalVariable) {
|
| DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
|
| DCHECK(FLAG_lazy_inner_functions);
|
| return var;
|
| @@ -1845,7 +1878,8 @@ VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope,
|
| if (var == nullptr) {
|
| proxy->set_next_unresolved(stack);
|
| stack = proxy;
|
| - } else if (var != kDummyPreParserVariable) {
|
| + } else if (var != kDummyPreParserVariable &&
|
| + var != kDummyPreParserLexicalVariable) {
|
| if (info != nullptr) {
|
| // In this case we need to leave scopes in a way that they can be
|
| // allocated. If we resolved variables from lazy parsed scopes, we need
|
|
|