| 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_) {
|
|
|