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 |