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); |
} |