Chromium Code Reviews| Index: src/ast/scopes.cc |
| diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc |
| index 4847c11214b6d61c1d15b3beb46f3ff2448eb8f3..6aa056edd9e26c471964c65fcb355f1a31be8039 100644 |
| --- a/src/ast/scopes.cc |
| +++ b/src/ast/scopes.cc |
| @@ -280,6 +280,7 @@ bool Scope::Analyze(ParseInfo* info) { |
| scope->Print(); |
| } |
| scope->CheckScopePositions(); |
| + scope->CheckZones(); |
| #endif |
| info->set_scope(scope); |
| @@ -505,6 +506,7 @@ Variable* Scope::LookupFunctionVar(const AstRawString* name, |
| VariableProxy* proxy = factory->NewVariableProxy(var); |
| VariableDeclaration* declaration = |
| factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); |
| + DCHECK_EQ(factory->zone(), zone()); |
| DeclareFunctionVar(declaration); |
| var->AllocateTo(VariableLocation::CONTEXT, index); |
| return var; |
| @@ -890,6 +892,62 @@ Handle<StringSet> Scope::CollectNonLocals(Handle<StringSet> non_locals) { |
| return non_locals; |
| } |
| +void Scope::CollectUnresolvableLocals(VariableProxy** still_unresolved, |
| + Scope* max_outer_scope) { |
| + BindingKind binding_kind; |
| + for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; |
| + proxy = next) { |
| + next = proxy->next_unresolved(); |
| + // Note that we pass nullptr as AstNodeFactory: this phase should not create |
| + // any new AstNodes, since none of the Scopes involved are backed up by |
|
adamk
2016/07/29 22:12:51
Is there an obvious place to add a DCHECK for this
marja
2016/08/01 11:02:50
I added a DCHECK_NOT_NULL(factory); statement in L
|
| + // ScopeInfo. |
| + if (LookupRecursive(proxy, &binding_kind, nullptr, max_outer_scope) == |
| + nullptr) { |
| + proxy->set_next_unresolved(*still_unresolved); |
| + *still_unresolved = proxy; |
| + } |
| + } |
| + |
| + for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| + scope->CollectUnresolvableLocals(still_unresolved, max_outer_scope); |
| + } |
| +} |
| + |
| +void Scope::AnalyzePartially(Scope* migrate_to, |
| + AstNodeFactory* ast_node_factory) { |
| + // Try to resolve unresolved variables for this Scope and collect those which |
| + // cannot be resolved inside. It doesn't make sense to try to resolve them in |
| + // the outer Scopes here, because they are incomplete. |
| + VariableProxy* still_unresolved = nullptr; |
| + CollectUnresolvableLocals(&still_unresolved, this); |
| + |
| + // Re-create the VariableProxies in the right Zone and insert them into |
| + // migrate_to. |
| + for (VariableProxy* proxy = still_unresolved; proxy != nullptr; |
| + proxy = proxy->next_unresolved()) { |
| + migrate_to->NewUnresolved( |
| + ast_node_factory, proxy->raw_name(), |
| + proxy->is_this() ? Variable::THIS : Variable::NORMAL, proxy->position(), |
|
adamk
2016/07/29 22:12:51
I had to go read some code to understand why you d
marja
2016/08/01 11:02:50
Yeah, this is not good, and it's also nontrivial t
|
| + proxy->end_position()); |
| + } |
| + |
| + // Gather info from inner scopes... |
| + PropagateScopeInfo(false); |
|
adamk
2016/07/29 22:12:51
This is called before variable resolution in Scope
marja
2016/08/01 11:02:50
I moved this call up, just to keep it more unified
|
| + |
| + // ... and push it up to migrate_to. Note that migrate_to and this Scope |
| + // describe the same Scope, just in different Zones. |
| + PropagateUsageFlagsToScope(migrate_to); |
| + if (inner_scope_calls_eval_) { |
| + migrate_to->inner_scope_calls_eval_ = true; |
| + } |
| + DCHECK(!force_eager_compilation_); |
| + migrate_to->set_start_position(start_position_); |
| + migrate_to->set_end_position(end_position_); |
| + migrate_to->language_mode_ = language_mode_; |
|
adamk
2016/07/29 22:12:51
One thing I'd recommend before submitting would be
marja
2016/08/01 11:02:50
Done: I didn't have these things from the start, a
|
| + outer_scope_->RemoveInnerScope(this); |
| + DCHECK_EQ(outer_scope_, migrate_to->outer_scope_); |
| + DCHECK_EQ(outer_scope_->zone(), migrate_to->zone()); |
| +} |
| #ifdef DEBUG |
| static const char* Header(ScopeType scope_type, FunctionKind function_kind, |
| @@ -1098,6 +1156,12 @@ void Scope::CheckScopePositions() { |
| scope->CheckScopePositions(); |
| } |
| } |
| + |
| +void Scope::CheckZones() { |
| + for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| + CHECK_EQ(scope->zone(), zone()); |
| + } |
| +} |
| #endif // DEBUG |
| @@ -1120,10 +1184,10 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { |
| return var; |
| } |
| - |
| Variable* Scope::LookupRecursive(VariableProxy* proxy, |
| BindingKind* binding_kind, |
| - AstNodeFactory* factory) { |
| + AstNodeFactory* factory, |
| + Scope* max_outer_scope) { |
| DCHECK(binding_kind != NULL); |
| if (already_resolved() && is_with_scope()) { |
| // Short-cut: if the scope is deserialized from a scope info, variable |
| @@ -1150,13 +1214,14 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, |
| var = LookupFunctionVar(proxy->raw_name(), factory); |
| if (var != NULL) { |
| *binding_kind = BOUND; |
| - } else if (outer_scope_ != NULL) { |
| - var = outer_scope_->LookupRecursive(proxy, binding_kind, factory); |
| + } else if (outer_scope_ != nullptr && this != max_outer_scope) { |
| + var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, |
| + max_outer_scope); |
| if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { |
| var->ForceContextAllocation(); |
| } |
| } else { |
| - DCHECK(is_script_scope()); |
| + DCHECK(is_script_scope() || this == max_outer_scope); |
| } |
| // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. |