Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Unified Diff: src/ast/scopes.cc

Issue 2262393004: Let LookupRecursive bind to NonLocals properly. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/ast/scopes.h ('k') | src/debug/debug-scopes.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
}
« no previous file with comments | « src/ast/scopes.h ('k') | src/debug/debug-scopes.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698