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

Unified Diff: src/scopes.cc

Issue 7904008: Introduce with scope and rework variable resolution. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 3 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
« src/scopes.h ('K') | « src/scopes.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/scopes.cc
diff --git a/src/scopes.cc b/src/scopes.cc
index d5a7a9f9ca8d7b86361856fa92bde29bbf796489..81038c6307c9a87c199d59decfc2cdee0039d26d 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -224,30 +224,31 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
bool contains_with = false;
while (!context->IsGlobalContext()) {
if (context->IsWithContext()) {
+ Scope* with_scope = new Scope(WITH_SCOPE);
Kevin Millikin (Chromium) 2011/09/15 09:38:13 Make the constructor take the current scope and ca
Steven 2011/09/15 19:54:06 There's already such a constructor that is used du
+ with_scope->AddInnerScope(current_scope);
+ current_scope = with_scope;
// All the inner scopes are inside a with.
contains_with = true;
for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
s->scope_inside_with_ = true;
}
+ } else if (context->IsFunctionContext()) {
+ SerializedScopeInfo* scope_info =
+ context->closure()->shared()->scope_info();
+ current_scope = new Scope(current_scope, FUNCTION_SCOPE,
+ Handle<SerializedScopeInfo>(scope_info));
+ } else if (context->IsBlockContext()) {
+ SerializedScopeInfo* scope_info =
+ SerializedScopeInfo::cast(context->extension());
+ current_scope = new Scope(current_scope, BLOCK_SCOPE,
+ Handle<SerializedScopeInfo>(scope_info));
} else {
- if (context->IsFunctionContext()) {
- SerializedScopeInfo* scope_info =
- context->closure()->shared()->scope_info();
- current_scope = new Scope(current_scope, FUNCTION_SCOPE,
- Handle<SerializedScopeInfo>(scope_info));
- } else if (context->IsBlockContext()) {
- SerializedScopeInfo* scope_info =
- SerializedScopeInfo::cast(context->extension());
- current_scope = new Scope(current_scope, BLOCK_SCOPE,
- Handle<SerializedScopeInfo>(scope_info));
- } else {
- ASSERT(context->IsCatchContext());
- String* name = String::cast(context->extension());
- current_scope = new Scope(current_scope, Handle<String>(name));
- }
- if (contains_with) current_scope->RecordWithStatement();
- if (innermost_scope == NULL) innermost_scope = current_scope;
+ ASSERT(context->IsCatchContext());
+ String* name = String::cast(context->extension());
+ current_scope = new Scope(current_scope, Handle<String>(name));
}
+ if (contains_with) current_scope->RecordWithStatement();
+ if (innermost_scope == NULL) innermost_scope = current_scope;
// Forget about a with when we move to a context for a different function.
if (context->previous()->closure() != context->closure()) {
@@ -300,7 +301,7 @@ void Scope::Initialize(bool inside_with) {
// instead load them directly from the stack. Currently, the only
// such parameter is 'this' which is passed on the stack when
// invoking scripts
- if (is_catch_scope() || is_block_scope()) {
+ if (is_catch_scope() || is_block_scope() || is_with_scope()) {
Kevin Millikin (Chromium) 2011/09/15 09:38:13 Flip the condition and use: if (is_declaration_sc
Steven 2011/09/15 19:54:06 Done.
ASSERT(outer_scope() != NULL);
receiver_ = outer_scope()->receiver();
} else {
@@ -516,7 +517,7 @@ Declaration* Scope::CheckConflictingVarDeclarations() {
}
// Include declaration scope in the iteration but stop after.
- if (!scope->is_block_scope() && !scope->is_catch_scope()) cond = false;
+ if (scope->is_declaration_scope()) cond = false;
}
}
return NULL;
@@ -627,8 +628,7 @@ int Scope::ContextChainLength(Scope* scope) {
Scope* Scope::DeclarationScope() {
Scope* scope = this;
- while (scope->is_catch_scope() ||
- scope->is_block_scope()) {
+ while (!scope->is_declaration_scope()) {
scope = scope->outer_scope();
}
return scope;
@@ -651,6 +651,7 @@ static const char* Header(Scope::Type type) {
case Scope::GLOBAL_SCOPE: return "global";
case Scope::CATCH_SCOPE: return "catch";
case Scope::BLOCK_SCOPE: return "block";
+ case Scope::WITH_SCOPE: return "with";
}
UNREACHABLE();
return NULL;
@@ -811,75 +812,61 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
}
-// Lookup a variable starting with this scope. The result is either
-// the statically resolved variable belonging to an outer scope, or
-// NULL. It may be NULL because a) we couldn't find a variable, or b)
-// because the variable is just a guess (and may be shadowed by
-// another variable that is introduced dynamically via an 'eval' call
-// or a 'with' statement).
-Variable* Scope::LookupRecursive(Handle<String> name,
- bool from_inner_scope,
- Variable** invalidated_local) {
- // If we find a variable, but the current scope calls 'eval', the found
- // variable may not be the correct one (the 'eval' may introduce a
- // property with the same name). In that case, remember that the variable
- // found is just a guess.
- bool guess = scope_calls_eval_;
-
+Scope::LookupResult Scope::LookupRecursive(Handle<String> name,
+ bool from_inner_scope,
+ Variable** var) {
// Try to find the variable in this scope.
- Variable* var = LocalLookup(name);
+ *var = LocalLookup(name);
- if (var != NULL) {
- // We found a variable. If this is not an inner lookup, we are done.
- // (Even if there is an 'eval' in this scope which introduces the
- // same variable again, the resulting variable remains the same.
- // Note that enclosing 'with' statements are handled at the call site.)
- if (!from_inner_scope)
- return var;
+ if (*var != NULL) {
+ // 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.)
- } else {
- // We did not find a variable locally. Check against the function variable,
- // if any. We can do this for all scopes, since the function variable is
- // only present - if at all - for function scopes.
- //
- // This lookup corresponds to a lookup in the "intermediate" scope sitting
- // between this scope and the outer scope. (ECMA-262, 3rd., requires that
- // the name of named function literal is kept in an intermediate scope
- // in between this scope and the next outer scope.)
- if (function_ != NULL && function_->name().is_identical_to(name)) {
- var = function_->var();
-
- } else if (outer_scope_ != NULL) {
- var = outer_scope_->LookupRecursive(name, true, invalidated_local);
- // We may have found a variable in an outer scope. However, if
- // the current scope is inside a 'with', the actual variable may
- // be a property introduced via the 'with' statement. Then, the
- // variable we may have found is just a guess.
- if (scope_inside_with_)
- guess = true;
+ // If this is a lookup from an inner scope, mark the variable.
+ if (from_inner_scope) {
+ (*var)->MarkAsAccessedFromInnerScope();
Kevin Millikin (Chromium) 2011/09/16 05:23:21 This is annoying to check here. Isn't it possible
Steven 2011/09/16 10:48:14 Sure, done. On 2011/09/16 05:23:21, Kevin Millikin
}
- // If we did not find a variable, we are done.
- if (var == NULL)
- return NULL;
- }
-
- ASSERT(var != NULL);
-
- // If this is a lookup from an inner scope, mark the variable.
- if (from_inner_scope) {
- var->MarkAsAccessedFromInnerScope();
+ if (is_global_scope()) return GLOBAL;
Kevin Millikin (Chromium) 2011/09/15 09:38:13 return is_global_scope() ? GLOBAL : FOUND; Though
Steven 2011/09/15 19:54:06 We need to distinguish locally bound variables fro
Kevin Millikin (Chromium) 2011/09/16 05:23:21 That's what I'm asking about. The old code will r
Steven 2011/09/16 10:48:14 Yes, I'm sorry you're right. The old code only thr
+ return FOUND;
}
- // If the variable we have found is just a guess, invalidate the
- // result. If the found variable is local, record that fact so we
- // can generate fast code to get it if it is not shadowed by eval.
- if (guess) {
- if (!var->is_global()) *invalidated_local = var;
- var = NULL;
+ // We did not find a variable locally. Check against the function variable,
+ // if any. We can do this for all scopes, since the function variable is
+ // only present - if at all - for function scopes.
+ //
+ // This lookup corresponds to a lookup in the "intermediate" scope sitting
+ // between this scope and the outer scope. (ECMA-262, 3rd., requires that
+ // the name of named function literal is kept in an intermediate scope
+ // in between this scope and the next outer scope.)
+ LookupResult result = GLOBAL;
+ if (function_ != NULL && function_->name().is_identical_to(name)) {
+ *var = function_->var();
+ if (from_inner_scope) {
+ (*var)->MarkAsAccessedFromInnerScope();
+ }
+ result = FOUND;
+ } else if (outer_scope_ != NULL) {
+ result = outer_scope_->LookupRecursive(name, true, var);
}
- return var;
+ // We may have found a variable in an outer scope. However, if the current
+ // scope is a 'with' scope, the actual variable may be a property introduced
+ // via the 'with' statement. Then, the variable we may have found is just a
+ // guess.
+ // Note that we must do a lookup in the outer scope anyway, because if we find
+ // one, we must mark that variable as potentially accessed from inside of an
+ // inner with scope (the property may not be in the 'with' object).
+ if (is_with_scope()) return FOUND_WITH;
+
+ // If we have found a variable in an outer scope, but the current scope calls
+ // 'eval', the found variable may not be the correct one (the 'eval' may
+ // introduce a property with the same name). In that case, remember that the
+ // variable found is just a guess.
+ if (result == FOUND && scope_calls_eval_) return FOUND_EVAL;
+
+ return result;
}
@@ -893,22 +880,30 @@ void Scope::ResolveVariable(Scope* global_scope,
if (proxy->var() != NULL) return;
// Otherwise, try to resolve the variable.
- Variable* invalidated_local = NULL;
- Variable* var = LookupRecursive(proxy->name(), false, &invalidated_local);
-
- if (proxy->inside_with()) {
- // If we are inside a local 'with' statement, all bets are off
- // and we cannot resolve the proxy to a local variable even if
- // we found an outer matching variable.
- // Note that we must do a lookup anyway, because if we find one,
- // we must mark that variable as potentially accessed from this
- // inner scope (the property may not be in the 'with' object).
- var = NonLocal(proxy->name(), Variable::DYNAMIC);
+ Variable* var = NULL;
+ LookupResult result = LookupRecursive(proxy->name(), false, &var);
- } else {
- // We are not inside a local 'with' statement.
+ switch (result) {
+ case FOUND:
+ break;
+
+ case FOUND_WITH:
+ // If we are inside a local 'with' statement, all bets are off
Kevin Millikin (Chromium) 2011/09/15 09:38:13 I lot of these comments are confusing and should b
Steven 2011/09/15 19:54:06 I cleaned them up. PTAL. On 2011/09/15 09:38:13, K
+ // and we cannot resolve the proxy to a local variable even if
+ // we found an outer matching variable.
+ var = NonLocal(proxy->name(), Variable::DYNAMIC);
+ break;
+
+ case FOUND_EVAL: {
+ // No with statements are involved and we found a local variable
+ // that might be shadowed by eval introduced variables.
+ Variable* invalidated_local = var;
+ var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
+ var->set_local_if_not_shadowed(invalidated_local);
+ break;
+ }
- if (var == NULL) {
+ case GLOBAL:
// We did not find the variable. We have a global variable
Kevin Millikin (Chromium) 2011/09/15 09:38:13 Or we did find it, and it was in the global scope.
Steven 2011/09/15 19:54:06 Eval in the global scope can't introduce shadowed
Kevin Millikin (Chromium) 2011/09/16 05:23:21 Yes, I know. Perhaps the names are a just bit off
Steven 2011/09/16 10:48:14 For BOUND it does indeed not matter much if the va
// if we are in the global scope (we know already that we
// are outside a 'with' statement) or if there is no way
@@ -926,15 +921,9 @@ void Scope::ResolveVariable(Scope* global_scope,
} else if (scope_inside_with_) {
// If we are inside a with statement we give up and look up
// the variable at runtime.
+ ASSERT(false);
Kevin Millikin (Chromium) 2011/09/15 09:38:13 Just get rid of this case completely and assert !s
Steven 2011/09/15 19:54:06 Sorry, this is dead code I forgot to delete. On 20
var = NonLocal(proxy->name(), Variable::DYNAMIC);
- } else if (invalidated_local != NULL) {
- // No with statements are involved and we found a local
- // variable that might be shadowed by eval introduced
- // variables.
- var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
- var->set_local_if_not_shadowed(invalidated_local);
-
} else if (outer_scope_is_eval_scope_) {
Kevin Millikin (Chromium) 2011/09/15 09:38:13 It would be great if we could get rid of this flag
Steven 2011/09/15 19:54:06 Got rid of the flag, but still need the propagate
// No with statements and we did not find a local and the code
// is executed with a call to eval. The context contains
@@ -943,7 +932,6 @@ void Scope::ResolveVariable(Scope* global_scope,
// variables.
if (context->GlobalIfNotShadowedByEval(proxy->name())) {
var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
-
} else {
var = NonLocal(proxy->name(), Variable::DYNAMIC);
}
@@ -955,9 +943,10 @@ void Scope::ResolveVariable(Scope* global_scope,
// variables.
var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
}
- }
+ break;
}
+ ASSERT(var != NULL);
proxy->BindTo(var);
}
« src/scopes.h ('K') | « src/scopes.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698