| Index: src/scopes.cc
|
| diff --git a/src/scopes.cc b/src/scopes.cc
|
| index 390a0b6e11ba8f1ccd4081fda789f582c8bc1554..eb0deb4964bb8cbc8ad5d1a151e381053c42bff1 100644
|
| --- a/src/scopes.cc
|
| +++ b/src/scopes.cc
|
| @@ -146,7 +146,9 @@ 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 +158,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 +234,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 +301,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 +569,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 +592,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;
|
| @@ -598,9 +618,11 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
|
| PrintF("; // ");
|
| if (var->rewrite() != NULL) {
|
| PrintF("%s, ", printer->Print(var->rewrite()));
|
| - if (var->is_accessed_from_inner_scope()) PrintF(", ");
|
| + if (var->is_accessed_from_inner_function_scope()) PrintF(", ");
|
| + }
|
| + if (var->is_accessed_from_inner_function_scope()) {
|
| + PrintF("inner scope access");
|
| }
|
| - if (var->is_accessed_from_inner_scope()) PrintF("inner scope access");
|
| PrintF("\n");
|
| }
|
| }
|
| @@ -721,7 +743,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
|
| // another variable that is introduced dynamically via an 'eval' call
|
| // or a 'with' statement).
|
| Variable* Scope::LookupRecursive(Handle<String> name,
|
| - bool inner_lookup,
|
| + bool from_inner_function,
|
| 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
|
| @@ -737,7 +759,7 @@ Variable* Scope::LookupRecursive(Handle<String> name,
|
| // (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 (!inner_lookup)
|
| + if (!from_inner_function)
|
| return var;
|
|
|
| } else {
|
| @@ -753,7 +775,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_function_scope() || from_inner_function,
|
| + 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
|
| @@ -770,8 +795,8 @@ Variable* Scope::LookupRecursive(Handle<String> name,
|
| ASSERT(var != NULL);
|
|
|
| // If this is a lookup from an inner scope, mark the variable.
|
| - if (inner_lookup) {
|
| - var->MarkAsAccessedFromInnerScope();
|
| + if (from_inner_function) {
|
| + var->MarkAsAccessedFromInnerFunctionScope();
|
| }
|
|
|
| // If the variable we have found is just a guess, invalidate the
|
| @@ -922,11 +947,12 @@ bool Scope::MustAllocate(Variable* var) {
|
| // via an eval() call. This is only possible if the variable has a
|
| // visible name.
|
| if ((var->is_this() || var->name()->length() > 0) &&
|
| - (var->is_accessed_from_inner_scope() ||
|
| + (var->is_accessed_from_inner_function_scope() ||
|
| 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,8 +969,8 @@ 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;
|
| - return var->is_accessed_from_inner_scope() ||
|
| + if (is_catch_scope() || is_block_scope()) return true;
|
| + return var->is_accessed_from_inner_function_scope() ||
|
| scope_calls_eval_ ||
|
| inner_scope_calls_eval_ ||
|
| scope_contains_with_ ||
|
| @@ -1010,7 +1036,7 @@ void Scope::AllocateParameterLocals() {
|
| if (uses_nonstrict_arguments) {
|
| // Give the parameter a use from an inner scope, to force allocation
|
| // to the context.
|
| - var->MarkAsAccessedFromInnerScope();
|
| + var->MarkAsAccessedFromInnerFunctionScope();
|
| }
|
|
|
| if (MustAllocate(var)) {
|
|
|