Chromium Code Reviews| Index: src/scopes.cc |
| diff --git a/src/scopes.cc b/src/scopes.cc |
| index 390a0b6e11ba8f1ccd4081fda789f582c8bc1554..84a02f0bdbe25425c1230ff4d4db5a584dcce4ba 100644 |
| --- a/src/scopes.cc |
| +++ b/src/scopes.cc |
| @@ -146,7 +146,7 @@ Scope::Scope(Scope* outer_scope, Type type) |
| } |
| -Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info) |
| +Scope::Scope(Scope* inner_scope, Type type, Handle<SerializedScopeInfo> scope_info) |
| : isolate_(Isolate::Current()), |
| inner_scopes_(4), |
| variables_(), |
| @@ -156,7 +156,7 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info) |
| decls_(4), |
| already_resolved_(true) { |
| ASSERT(!scope_info.is_null()); |
| - SetDefaults(FUNCTION_SCOPE, NULL, scope_info); |
| + SetDefaults(type, NULL, scope_info); |
| if (scope_info->HasHeapAllocatedLocals()) { |
| num_heap_slots_ = scope_info_->NumberOfContextSlots(); |
| } |
| @@ -232,8 +232,13 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info, |
| if (context->IsFunctionContext()) { |
| SerializedScopeInfo* scope_info = |
| context->closure()->shared()->scope_info(); |
| - current_scope = |
| - new Scope(current_scope, Handle<SerializedScopeInfo>(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()); |
| @@ -294,10 +299,13 @@ 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()) { |
| + if (is_catch_scope() || is_block_scope()) { |
| ASSERT(outer_scope() != NULL); |
| receiver_ = outer_scope()->receiver(); |
| } else { |
| + ASSERT(is_function_scope() || |
| + is_global_scope() || |
| + is_eval_scope()); |
| Variable* var = |
| variables_.Declare(this, |
| isolate_->factory()->this_symbol(), |
| @@ -559,13 +567,22 @@ int Scope::ContextChainLength(Scope* scope) { |
| Scope* Scope::DeclarationScope() { |
| Scope* scope = this; |
| - while (scope->is_catch_scope()) { |
| + while (scope->is_catch_scope() || |
| + scope->is_block_scope()) { |
| scope = scope->outer_scope(); |
| } |
| return scope; |
| } |
| +Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() { |
| + if (scope_info_.is_null()) { |
| + scope_info_ = SerializedScopeInfo::Create(this); |
| + } |
| + return scope_info_; |
| +} |
| + |
| + |
| #ifdef DEBUG |
| static const char* Header(Scope::Type type) { |
| switch (type) { |
| @@ -573,6 +590,7 @@ static const char* Header(Scope::Type type) { |
| case Scope::FUNCTION_SCOPE: return "function"; |
| case Scope::GLOBAL_SCOPE: return "global"; |
| case Scope::CATCH_SCOPE: return "catch"; |
| + case Scope::BLOCK_SCOPE: return "block"; |
| } |
| UNREACHABLE(); |
| return NULL; |
| @@ -753,7 +771,10 @@ Variable* Scope::LookupRecursive(Handle<String> name, |
| var = function_; |
| } else if (outer_scope_ != NULL) { |
| - var = outer_scope_->LookupRecursive(name, true, invalidated_local); |
| + var = outer_scope_->LookupRecursive( |
| + name, |
| + is_block_scope() || is_catch_scope() ? inner_lookup : true, |
|
Kevin Millikin (Chromium)
2011/08/10 11:19:27
This is subtle. I'd probably change all the ident
Steven
2011/08/10 12:21:00
Done.
|
| + 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 |
| @@ -926,7 +947,8 @@ bool Scope::MustAllocate(Variable* var) { |
| scope_calls_eval_ || |
| inner_scope_calls_eval_ || |
| scope_contains_with_ || |
| - is_catch_scope())) { |
| + is_catch_scope() || |
| + is_block_scope())) { |
| var->set_is_used(true); |
| } |
| // Global variables do not need to be allocated. |
| @@ -943,7 +965,7 @@ bool Scope::MustAllocateInContext(Variable* var) { |
| // Exceptions: temporary variables are never allocated in a context; |
| // catch-bound variables are always allocated in a context. |
| if (var->mode() == Variable::TEMPORARY) return false; |
| - if (is_catch_scope()) return true; |
| + if (is_catch_scope() || is_block_scope()) return true; |
| return var->is_accessed_from_inner_scope() || |
| scope_calls_eval_ || |
| inner_scope_calls_eval_ || |