| Index: runtime/vm/scopes.cc
|
| diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
|
| index e11fc166824a221e77870d896328f312cb0eb0ab..637e9b72bfa92fa9e1a9a19be20e4290c0722e7c 100644
|
| --- a/runtime/vm/scopes.cc
|
| +++ b/runtime/vm/scopes.cc
|
| @@ -404,18 +404,10 @@ LocalVariable* LocalScope::LookupVariable(const String& name, bool test_only) {
|
| LocalScope* current_scope = this;
|
| while (current_scope != NULL) {
|
| LocalVariable* var = current_scope->LocalLookupVariable(name);
|
| - if ((var != NULL) && !var->is_invisible_) {
|
| - if (!test_only) {
|
| - if (var->owner()->function_level() != function_level()) {
|
| - var->set_is_captured();
|
| - }
|
| - // Insert aliases of the variable in intermediate scopes.
|
| - LocalScope* intermediate_scope = this;
|
| - while (intermediate_scope != current_scope) {
|
| - intermediate_scope->variables_.Add(var);
|
| - ASSERT(var->owner() != intermediate_scope); // Item is an alias.
|
| - intermediate_scope = intermediate_scope->parent();
|
| - }
|
| + // If testing only, return the variable even if invisible.
|
| + if ((var != NULL) && (!var->is_invisible_ || test_only)) {
|
| + if (!test_only && (var->owner()->function_level() != function_level())) {
|
| + CaptureVariable(var);
|
| }
|
| return var;
|
| }
|
| @@ -425,32 +417,29 @@ LocalVariable* LocalScope::LookupVariable(const String& name, bool test_only) {
|
| }
|
|
|
|
|
| -bool LocalScope::CaptureVariable(const String& name) {
|
| - ASSERT(name.IsSymbol());
|
| - LocalScope* current_scope = this;
|
| - while (current_scope != NULL) {
|
| - LocalVariable* var = current_scope->LocalLookupVariable(name);
|
| - if (var != NULL) {
|
| - var->set_is_captured();
|
| - LocalScope* scope = this;
|
| - while (var->owner()->function_level() != scope->function_level()) {
|
| - // Insert an alias of the variable in the top scope of each function
|
| - // level so that the variable is found in the context.
|
| - LocalScope* parent_scope = scope->parent();
|
| - while ((parent_scope != NULL) &&
|
| - (parent_scope->function_level() == scope->function_level())) {
|
| - scope = parent_scope;
|
| - parent_scope = scope->parent();
|
| - }
|
| - scope->variables_.Add(var);
|
| - ASSERT(var->owner() != scope); // Item is an alias.
|
| - scope = parent_scope;
|
| - }
|
| - return true;
|
| +void LocalScope::CaptureVariable(LocalVariable* variable) {
|
| + ASSERT(variable != NULL);
|
| + // The variable must exist in an enclosing scope, not necessarily in this one.
|
| + variable->set_is_captured();
|
| + const int variable_function_level = variable->owner()->function_level();
|
| + LocalScope* scope = this;
|
| + while (scope->function_level() != variable_function_level) {
|
| + // Insert an alias of the variable in the top scope of each function
|
| + // level so that the variable is found in the context.
|
| + LocalScope* parent_scope = scope->parent();
|
| + while ((parent_scope != NULL) &&
|
| + (parent_scope->function_level() == scope->function_level())) {
|
| + scope = parent_scope;
|
| + parent_scope = scope->parent();
|
| }
|
| - current_scope = current_scope->parent();
|
| + // An alias may already have been added in this scope, and in that case,
|
| + // in parent scopes as needed. If so, we are done.
|
| + if (!scope->AddVariable(variable)) {
|
| + return;
|
| + }
|
| + ASSERT(variable->owner() != scope); // Item is an alias.
|
| + scope = parent_scope;
|
| }
|
| - return false;
|
| }
|
|
|
|
|
| @@ -525,9 +514,10 @@ SourceLabel* LocalScope::CheckUnresolvedLabels() {
|
|
|
| int LocalScope::NumCapturedVariables() const {
|
| // It is not necessary to traverse parent scopes, since we are only interested
|
| - // in the captured variables referenced in this scope. If this scope
|
| - // references a captured variable declared in a parent scope, it will contain
|
| - // an alias for that variable.
|
| + // in the captured variables referenced in this scope. If this scope is the
|
| + // top scope at function level 1 and it (or its children scopes) references a
|
| + // captured variable declared in a parent scope at function level 0, it will
|
| + // contain an alias for that variable.
|
|
|
| // Since code generation for nested functions is postponed until first
|
| // invocation, the function level of the closure scope can only be 1.
|
| @@ -628,7 +618,6 @@ LocalScope* LocalScope::RestoreOuterScope(const ContextScope& context_scope) {
|
|
|
|
|
| void LocalScope::RecursivelyCaptureAllVariables() {
|
| - bool found = false;
|
| for (intptr_t i = 0; i < num_variables(); i++) {
|
| if ((VariableAt(i)->name().raw() == Symbols::StackTraceVar().raw()) ||
|
| (VariableAt(i)->name().raw() == Symbols::ExceptionVar().raw()) ||
|
| @@ -637,8 +626,7 @@ void LocalScope::RecursivelyCaptureAllVariables() {
|
| // stack.
|
| continue;
|
| }
|
| - found = CaptureVariable(VariableAt(i)->name());
|
| - ASSERT(found);
|
| + CaptureVariable(VariableAt(i));
|
| }
|
| if (sibling() != NULL) { sibling()->RecursivelyCaptureAllVariables(); }
|
| if (child() != NULL) { child()->RecursivelyCaptureAllVariables(); }
|
|
|