Index: src/scopes.cc |
=================================================================== |
--- src/scopes.cc (revision 1289) |
+++ src/scopes.cc (working copy) |
@@ -139,6 +139,7 @@ |
scope_calls_eval_(false), |
outer_scope_calls_eval_(false), |
inner_scope_calls_eval_(false), |
+ outer_scope_is_eval_scope_(false), |
force_eager_compilation_(false), |
num_stack_slots_(0), |
num_heap_slots_(0) { |
@@ -312,7 +313,8 @@ |
// and assume they may invoke eval themselves. Eventually we could capture |
// this information in the ScopeInfo and then use it here (by traversing |
// the call chain stack, at compile time). |
- PropagateScopeInfo(is_eval_scope()); |
+ bool eval_scope = is_eval_scope(); |
+ PropagateScopeInfo(eval_scope, eval_scope); |
// 2) Resolve variables. |
Scope* global_scope = NULL; |
@@ -442,6 +444,7 @@ |
if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n"); |
if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n"); |
if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n"); |
+ if (outer_scope_is_eval_scope_) Indent(n1, "// outer scope is 'eval' scope\n"); |
if (num_stack_slots_ > 0) { Indent(n1, "// "); |
PrintF("%d stack slots\n", num_stack_slots_); } |
if (num_heap_slots_ > 0) { Indent(n1, "// "); |
@@ -482,20 +485,18 @@ |
#endif // DEBUG |
-Variable* Scope::NonLocal(Handle<String> name) { |
- // Space optimization: reuse existing non-local with the same name. |
+Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) { |
+ // Space optimization: reuse existing non-local with the same name |
+ // and mode. |
for (int i = 0; i < nonlocals_.length(); i++) { |
Variable* var = nonlocals_[i]; |
- if (var->name().is_identical_to(name)) { |
- ASSERT(var->mode() == Variable::DYNAMIC); |
+ if (var->name().is_identical_to(name) && var->mode() == mode) { |
return var; |
} |
} |
- // Otherwise create a new new-local and add it to the list. |
- Variable* var = new Variable( |
- NULL /* we don't know the scope */, |
- name, Variable::DYNAMIC, true, false); |
+ // Otherwise create a new non-local and add it to the list. |
+ Variable* var = new Variable(NULL, name, mode, true, false); |
nonlocals_.Add(var); |
// Allocate it by giving it a dynamic lookup. |
@@ -511,7 +512,9 @@ |
// 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 inner_lookup) { |
+Variable* Scope::LookupRecursive(Handle<String> name, |
+ bool inner_lookup, |
+ 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 |
@@ -542,7 +545,7 @@ |
var = function_; |
} else if (outer_scope_ != NULL) { |
- var = outer_scope_->LookupRecursive(name, true /* inner lookup */); |
+ 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 |
@@ -563,8 +566,10 @@ |
var->is_accessed_from_inner_scope_ = true; |
// If the variable we have found is just a guess, invalidate the result. |
- if (guess) |
+ if (guess) { |
+ *invalidated_local = var; |
var = NULL; |
+ } |
return var; |
} |
@@ -578,7 +583,8 @@ |
if (proxy->var() != NULL) return; |
// Otherwise, try to resolve the variable. |
- Variable* var = LookupRecursive(proxy->name(), false); |
+ 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 |
@@ -587,7 +593,7 @@ |
// 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()); |
+ var = NonLocal(proxy->name(), Variable::DYNAMIC); |
} else { |
// We are not inside a local 'with' statement. |
@@ -601,12 +607,23 @@ |
// or we don't know about the outer scope (because we are |
// in an eval scope). |
if (!is_global_scope() && |
- (is_eval_scope() || outer_scope_calls_eval_ || |
- scope_calls_eval_ || scope_inside_with_)) { |
- // We must look up the variable at runtime, and we don't |
- // know anything else. |
- var = NonLocal(proxy->name()); |
+ (scope_inside_with_ || outer_scope_is_eval_scope_)) { |
+ // If we are inside a with statement or the code is executed |
+ // using eval, we give up and look up the variable at runtime. |
+ var = NonLocal(proxy->name(), Variable::DYNAMIC); |
+ } else if (!is_global_scope() && |
+ (scope_calls_eval_ || outer_scope_calls_eval_)) { |
+ // If the code is not executed using eval and there are no |
+ // with scopes, either we have a local or a global variable |
+ // that might be shadowed by an eval-introduced variable. |
+ if (invalidated_local != NULL) { |
+ var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL); |
+ var->set_local_if_not_shadowed(invalidated_local); |
+ } else { |
+ var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL); |
+ } |
+ |
} else { |
// We must have a global variable. |
ASSERT(global_scope != NULL); |
@@ -643,15 +660,21 @@ |
} |
-bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval) { |
+bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval, |
+ bool outer_scope_is_eval_scope) { |
if (outer_scope_calls_eval) { |
outer_scope_calls_eval_ = true; |
} |
- bool b = scope_calls_eval_ || outer_scope_calls_eval_; |
+ if (outer_scope_is_eval_scope) { |
+ outer_scope_is_eval_scope_ = true; |
+ } |
+ |
+ bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_; |
+ bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_; |
for (int i = 0; i < inner_scopes_.length(); i++) { |
Scope* inner_scope = inner_scopes_[i]; |
- if (inner_scope->PropagateScopeInfo(b)) { |
+ if (inner_scope->PropagateScopeInfo(calls_eval, is_eval)) { |
inner_scope_calls_eval_ = true; |
} |
if (inner_scope->force_eager_compilation_) { |