Index: src/ast/scopes.cc |
diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc |
index 7689786ce46606f07090155b3e0194f777c3cdad..fbc29609fd06ef80a112e561e69f78ae42789286 100644 |
--- a/src/ast/scopes.cc |
+++ b/src/ast/scopes.cc |
@@ -272,10 +272,14 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, |
} |
current_scope = with_scope; |
} else if (context->IsScriptContext()) { |
+ // If we reach a script context, it's the outermost context with scope |
+ // info. The next context will be the native context. Install the scope |
+ // info of this script context onto the existing script scope to avoid |
+ // nesting script scopes. |
Handle<ScopeInfo> scope_info(context->scope_info(), isolate); |
- DCHECK_EQ(scope_info->scope_type(), SCRIPT_SCOPE); |
- current_scope = new (zone) |
- DeclarationScope(zone, current_scope, SCRIPT_SCOPE, scope_info); |
+ script_scope->SetScriptScopeInfo(scope_info); |
+ DCHECK(context->previous()->IsNativeContext()); |
+ break; |
} else if (context->IsFunctionContext()) { |
Handle<ScopeInfo> scope_info(context->closure()->shared()->scope_info(), |
isolate); |
@@ -313,9 +317,10 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, |
context = context->previous(); |
} |
+ if (innermost_scope == nullptr) return script_scope; |
script_scope->AddInnerScope(current_scope); |
script_scope->PropagateScopeInfo(); |
- return (innermost_scope == NULL) ? script_scope : innermost_scope; |
+ return innermost_scope; |
} |
void Scope::DeserializeScopeInfo(Isolate* isolate, |
@@ -422,11 +427,7 @@ void Scope::Analyze(ParseInfo* info) { |
scope->outer_scope()->scope_type() == SCRIPT_SCOPE || |
scope->outer_scope()->already_resolved_); |
- // Allocate the variables. |
- { |
- AstNodeFactory ast_node_factory(info->ast_value_factory()); |
- scope->AllocateVariables(info, &ast_node_factory); |
- } |
+ scope->AllocateVariables(info); |
#ifdef DEBUG |
if (info->script_is_native() ? FLAG_print_builtin_scopes |
@@ -844,13 +845,12 @@ void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals, |
} |
} |
-void DeclarationScope::AllocateVariables(ParseInfo* info, |
- AstNodeFactory* factory) { |
+void DeclarationScope::AllocateVariables(ParseInfo* info) { |
// 1) Propagate scope information. |
PropagateScopeInfo(); |
// 2) Resolve variables. |
- ResolveVariablesRecursively(info, factory); |
+ ResolveVariablesRecursively(info); |
// 3) Allocate variables. |
AllocateVariablesRecursively(); |
@@ -1229,13 +1229,9 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { |
return var; |
} |
-Variable* Scope::LookupRecursive(VariableProxy* proxy, |
- BindingKind* binding_kind, |
- AstNodeFactory* factory, |
+Variable* Scope::LookupRecursive(VariableProxy* proxy, bool declare_free, |
Scope* outer_scope_end) { |
DCHECK_NE(outer_scope_end, this); |
- DCHECK_NOT_NULL(binding_kind); |
- DCHECK_EQ(UNBOUND, *binding_kind); |
// Short-cut: whenever we find a debug-evaluate scope, just look everything up |
// dynamically. Debug-evaluate doesn't properly create scope info for the |
// lookups it does. It may not have a valid 'this' declaration, and anything |
@@ -1244,8 +1240,8 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, |
// TODO(yangguo): Remove once debug-evaluate creates proper ScopeInfo for the |
// scopes in which it's evaluating. |
if (is_debug_evaluate_scope_) { |
- *binding_kind = DYNAMIC_LOOKUP; |
- return nullptr; |
+ if (!declare_free) return nullptr; |
+ return NonLocal(proxy->raw_name(), DYNAMIC); |
} |
// Try to find the variable in this scope. |
@@ -1254,54 +1250,58 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, |
// We found a variable and we are done. (Even if there is an 'eval' in this |
// scope which introduces the same variable again, the resulting variable |
// remains the same.) |
- if (var != nullptr) { |
- *binding_kind = BOUND; |
- return var; |
- } |
+ if (var != nullptr) return var; |
// We did not find a variable locally. Check against the function variable, if |
// any. |
if (is_function_scope()) { |
var = AsDeclarationScope()->LookupFunctionVar(proxy->raw_name()); |
if (var != nullptr) { |
- *binding_kind = calls_sloppy_eval() ? BOUND_EVAL_SHADOWED : BOUND; |
+ if (calls_sloppy_eval()) return NonLocal(proxy->raw_name(), DYNAMIC); |
return var; |
} |
} |
- if (outer_scope_ != outer_scope_end) { |
- var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, |
- outer_scope_end); |
- if (*binding_kind == BOUND && is_function_scope()) { |
+ if (outer_scope_ == outer_scope_end) { |
+ if (!declare_free) return nullptr; |
+ DCHECK(is_script_scope()); |
+ // No binding has been found. Declare a variable on the global object. |
+ return AsDeclarationScope()->DeclareDynamicGlobal(proxy->raw_name(), |
+ Variable::NORMAL); |
+ } |
+ |
+ DCHECK(!is_script_scope()); |
+ |
+ var = outer_scope_->LookupRecursive(proxy, declare_free, outer_scope_end); |
+ |
+ // The variable could not be resolved statically. |
+ if (var == nullptr) return var; |
+ |
+ if (is_function_scope() && !var->is_dynamic()) { |
+ var->ForceContextAllocation(); |
+ } |
+ // "this" can't be shadowed by "eval"-introduced bindings or by "with" |
+ // scopes. |
+ // TODO(wingo): There are other variables in this category; add them. |
+ if (var->is_this()) return var; |
+ |
+ if (is_with_scope()) { |
+ // The current scope is a with scope, so the variable binding can not be |
+ // statically resolved. However, note that it was necessary to do a lookup |
+ // in the outer scope anyway, because if a binding exists in an outer |
+ // scope, the associated variable has to be marked as potentially being |
+ // accessed from inside of an inner with scope (the property may not be in |
+ // the 'with' object). |
+ if (!var->is_dynamic() && var->IsUnallocated()) { |
+ DCHECK(!already_resolved_); |
+ var->set_is_used(); |
var->ForceContextAllocation(); |
+ if (proxy->is_assigned()) var->set_maybe_assigned(); |
} |
- // "this" can't be shadowed by "eval"-introduced bindings or by "with" |
- // scopes. |
- // TODO(wingo): There are other variables in this category; add them. |
- if (var != nullptr && var->is_this()) return var; |
- |
- if (is_with_scope()) { |
- // The current scope is a with scope, so the variable binding can not be |
- // statically resolved. However, note that it was necessary to do a lookup |
- // in the outer scope anyway, because if a binding exists in an outer |
- // scope, the associated variable has to be marked as potentially being |
- // accessed from inside of an inner with scope (the property may not be in |
- // the 'with' object). |
- if (var != nullptr && var->IsUnallocated()) { |
- DCHECK(!already_resolved_); |
- var->set_is_used(); |
- var->ForceContextAllocation(); |
- if (proxy->is_assigned()) var->set_maybe_assigned(); |
- } |
- *binding_kind = DYNAMIC_LOOKUP; |
- return nullptr; |
- } |
- } else { |
- DCHECK(!is_with_scope()); |
- DCHECK(is_function_scope() || is_script_scope() || is_eval_scope()); |
+ return NonLocal(proxy->raw_name(), DYNAMIC); |
} |
- if (calls_sloppy_eval() && is_declaration_scope() && !is_script_scope()) { |
+ if (calls_sloppy_eval() && is_declaration_scope()) { |
// A variable binding may have been found in an outer scope, but the current |
// scope makes a sloppy 'eval' call, so the found variable may not be the |
// correct one (the 'eval' may introduce a binding with the same name). In |
@@ -1309,18 +1309,21 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, |
// scopes that can host var bindings (declaration scopes) need be considered |
// here (this excludes block and catch scopes), and variable lookups at |
// script scope are always dynamic. |
- if (*binding_kind == BOUND) { |
- *binding_kind = BOUND_EVAL_SHADOWED; |
- } else if (*binding_kind == UNBOUND) { |
- *binding_kind = UNBOUND_EVAL_SHADOWED; |
+ if (var->IsGlobalObjectProperty()) { |
+ return NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
} |
+ |
+ if (var->is_dynamic()) return var; |
+ |
+ Variable* invalidated = var; |
+ var = NonLocal(proxy->raw_name(), DYNAMIC_LOCAL); |
+ var->set_local_if_not_shadowed(invalidated); |
} |
return var; |
} |
-void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy, |
- AstNodeFactory* factory) { |
+void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy) { |
DCHECK(info->script_scope()->is_script_scope()); |
// If the proxy is already resolved there's nothing to do |
@@ -1328,21 +1331,19 @@ void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy, |
if (proxy->is_resolved()) return; |
// Otherwise, try to resolve the variable. |
- BindingKind binding_kind = UNBOUND; |
- Variable* var = LookupRecursive(proxy, &binding_kind, factory); |
+ Variable* var = LookupRecursive(proxy, true, nullptr); |
- ResolveTo(info, binding_kind, proxy, var); |
+ ResolveTo(info, proxy, var); |
} |
-void Scope::ResolveTo(ParseInfo* info, BindingKind binding_kind, |
- VariableProxy* proxy, Variable* var) { |
+void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { |
#ifdef DEBUG |
if (info->script_is_native()) { |
// To avoid polluting the global object in native scripts |
// - Variables must not be allocated to the global scope. |
CHECK_NOT_NULL(outer_scope()); |
// - Variables must be bound locally or unallocated. |
- if (BOUND != binding_kind) { |
+ if (var->IsGlobalObjectProperty()) { |
// The following variable name may be minified. If so, disable |
// minification in js2c.py for better output. |
Handle<String> name = proxy->raw_name()->string(); |
@@ -1357,62 +1358,23 @@ void Scope::ResolveTo(ParseInfo* info, BindingKind binding_kind, |
} |
#endif |
- switch (binding_kind) { |
- case BOUND: |
- break; |
- |
- case BOUND_EVAL_SHADOWED: |
- // We either found a variable binding that might be shadowed by eval or |
- // gave up on it (e.g. by encountering a local with the same in the outer |
- // scope which was not promoted to a context, this can happen if we use |
- // debugger to evaluate arbitrary expressions at a break point). |
- if (var->IsGlobalObjectProperty()) { |
- var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
- } else if (var->is_dynamic()) { |
- var = NonLocal(proxy->raw_name(), DYNAMIC); |
- } else { |
- Variable* invalidated = var; |
- var = NonLocal(proxy->raw_name(), DYNAMIC_LOCAL); |
- var->set_local_if_not_shadowed(invalidated); |
- } |
- break; |
- |
- case UNBOUND: |
- // No binding has been found. Declare a variable on the global object. |
- var = info->script_scope()->DeclareDynamicGlobal(proxy->raw_name(), |
- Variable::NORMAL); |
- break; |
- |
- case UNBOUND_EVAL_SHADOWED: |
- // No binding has been found. But some scope makes a sloppy 'eval' call. |
- var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
- break; |
- |
- case DYNAMIC_LOOKUP: |
- // The variable could not be resolved statically. |
- var = NonLocal(proxy->raw_name(), DYNAMIC); |
- break; |
- } |
- |
- DCHECK(var != NULL); |
+ DCHECK_NOT_NULL(var); |
if (proxy->is_assigned()) var->set_maybe_assigned(); |
- |
proxy->BindTo(var); |
} |
-void Scope::ResolveVariablesRecursively(ParseInfo* info, |
- AstNodeFactory* factory) { |
+void Scope::ResolveVariablesRecursively(ParseInfo* info) { |
DCHECK(info->script_scope()->is_script_scope()); |
// Resolve unresolved variables for this scope. |
for (VariableProxy* proxy = unresolved_; proxy != nullptr; |
proxy = proxy->next_unresolved()) { |
- ResolveVariable(info, proxy, factory); |
+ ResolveVariable(info, proxy); |
} |
// Resolve unresolved variables for inner scopes. |
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
- scope->ResolveVariablesRecursively(info, factory); |
+ scope->ResolveVariablesRecursively(info); |
} |
} |
@@ -1423,19 +1385,13 @@ VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, |
proxy = next) { |
next = proxy->next_unresolved(); |
if (proxy->is_resolved()) continue; |
- // 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 |
- // ScopeInfo. |
- BindingKind binding_kind = UNBOUND; |
- Variable* var = LookupRecursive(proxy, &binding_kind, nullptr, |
- max_outer_scope->outer_scope()); |
+ Variable* var = |
+ LookupRecursive(proxy, false, max_outer_scope->outer_scope()); |
if (var == nullptr) { |
proxy->set_next_unresolved(stack); |
stack = proxy; |
} else if (info != nullptr) { |
- DCHECK_NE(UNBOUND, binding_kind); |
- DCHECK_NE(UNBOUND_EVAL_SHADOWED, binding_kind); |
- ResolveTo(info, binding_kind, proxy, var); |
+ ResolveTo(info, proxy, var); |
} |
} |