diff --git a/src/heap.h b/src/heap.h index 0f69fab391..8eb42d3a31 100644 --- a/src/heap.h +++ b/src/heap.h @@ -225,8 +225,7 @@ inline Heap* _inline_get_heap_(); V(closure_symbol, "(closure)") \ V(use_strict, "use strict") \ V(dot_symbol, ".") \ - V(anonymous_function_symbol, "(anonymous function)") \ - V(block_scope_symbol, ".block") + V(anonymous_function_symbol, "(anonymous function)") // Forward declarations. class GCTracer; diff --git a/src/parser.cc b/src/parser.cc index d685b8a344..a863165b01 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1559,9 +1559,6 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { Scope* block_scope = NewScope(top_scope_, Scope::BLOCK_SCOPE, inside_with()); - body->set_block_scope(block_scope); - block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(), - Variable::VAR); if (top_scope_->is_strict_mode()) { block_scope->EnableStrictMode(); } @@ -1584,21 +1581,28 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { } } Expect(Token::RBRACE, CHECK_OK); - - // Create exit block. - Block* exit = new(zone()) Block(isolate(), NULL, 1, false); - exit->AddStatement(new(zone()) ExitContextStatement()); - - // Create a try-finally statement. - TryFinallyStatement* try_finally = - new(zone()) TryFinallyStatement(body, exit); - try_finally->set_escaping_targets(collector.targets()); top_scope_ = saved_scope; - // Create a result block. - Block* result = new(zone()) Block(isolate(), NULL, 1, false); - result->AddStatement(try_finally); - return result; + block_scope = block_scope->FinalizeBlockScope(); + body->set_block_scope(block_scope); + + if (block_scope != NULL) { + // Create exit block. + Block* exit = new(zone()) Block(isolate(), NULL, 1, false); + exit->AddStatement(new(zone()) ExitContextStatement()); + + // Create a try-finally statement. + TryFinallyStatement* try_finally = + new(zone()) TryFinallyStatement(body, exit); + try_finally->set_escaping_targets(collector.targets()); + + // Create a result block. + Block* result = new(zone()) Block(isolate(), NULL, 1, false); + result->AddStatement(try_finally); + return result; + } else { + return body; + } } diff --git a/src/scopes.cc b/src/scopes.cc index b2958db60f..15634d0951 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -331,6 +331,35 @@ void Scope::Initialize(bool inside_with) { } +Scope* Scope::FinalizeBlockScope() { + ASSERT(is_block_scope()); + ASSERT(temps_.is_empty()); + ASSERT(params_.is_empty()); + + if (num_var_or_const() > 0) return this; + + // Remove this scope from outer scope. + for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) { + if (outer_scope_->inner_scopes_[i] == this) { + outer_scope_->inner_scopes_.Remove(i); + break; + } + } + + // Reparent inner scopes. + for (int i = 0; i < inner_scopes_.length(); i++) { + outer_scope()->AddInnerScope(inner_scopes_[i]); + } + + // Move unresolved variables + for (int i = 0; i < unresolved_.length(); i++) { + outer_scope()->unresolved_.Add(unresolved_[i]); + } + + return NULL; +} + + Variable* Scope::LocalLookup(Handle name) { Variable* result = variables_.Lookup(name); if (result != NULL || scope_info_.is_null()) { diff --git a/src/scopes.h b/src/scopes.h index a01d9c7d47..d18c6bc274 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -112,6 +112,11 @@ class Scope: public ZoneObject { void Initialize(bool inside_with); + // Checks if the block scope is redundant, i.e. it does not contain any + // block scoped declarations. In that case it is removed from the scope + // tree and its children are reparented. + Scope* FinalizeBlockScope(); + // --------------------------------------------------------------------------- // Declarations diff --git a/test/mjsunit/harmony/debug-blockscopes.js b/test/mjsunit/harmony/debug-blockscopes.js index e0df71b2df..d02c9f6a8e 100644 --- a/test/mjsunit/harmony/debug-blockscopes.js +++ b/test/mjsunit/harmony/debug-blockscopes.js @@ -202,17 +202,15 @@ function local_block_1() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.Local, + CheckScopeChain([debug.ScopeType.Local, debug.ScopeType.Global], exec_state); CheckScopeContent({}, 0, exec_state); - CheckScopeContent({}, 1, exec_state); }; local_block_1(); EndTest(); -// Local scope with a parameter. +// Simple empty block scope in local scope with a parameter. BeginTest("Local 2"); function local_2(a) { @@ -222,10 +220,9 @@ function local_2(a) { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.Local, + CheckScopeChain([debug.ScopeType.Local, debug.ScopeType.Global], exec_state); - CheckScopeContent({a:1}, 1, exec_state); + CheckScopeContent({a:1}, 0, exec_state); }; local_2(1); EndTest(); @@ -266,6 +263,72 @@ local_4(1, 2); EndTest(); +// Single variable in a block scope. +BeginTest("Local 5"); + +function local_5(a) { + { + let x = 5; + debugger; + } +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x:5}, 0, exec_state); + CheckScopeContent({a:1}, 1, exec_state); +}; +local_5(1); +EndTest(); + + +// Two variables in a block scope. +BeginTest("Local 6"); + +function local_6(a) { + { + let x = 6; + let y = 7; + debugger; + } +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x:6,y:7}, 0, exec_state); + CheckScopeContent({a:1}, 1, exec_state); +}; +local_6(1); +EndTest(); + + +// Two variables in a block scope. +BeginTest("Local 7"); + +function local_7(a) { + { + { + let x = 8; + debugger; + } + } +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x:8}, 0, exec_state); + CheckScopeContent({a:1}, 1, exec_state); +}; +local_7(1); +EndTest(); + + // Single empty with block. BeginTest("With block 1"); @@ -276,8 +339,7 @@ function with_block_1() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); CheckScopeContent({}, 0, exec_state); @@ -299,16 +361,13 @@ function with_block_2() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, - debug.ScopeType.Block, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); CheckScopeContent({}, 0, exec_state); CheckScopeContent({}, 1, exec_state); CheckScopeContent({}, 2, exec_state); - CheckScopeContent({}, 3, exec_state); }; with_block_2(); EndTest(); @@ -324,12 +383,10 @@ function with_block_3() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); - CheckScopeContent({}, 0, exec_state); - CheckScopeContent({a:1,b:2}, 1, exec_state); + CheckScopeContent({a:1,b:2}, 0, exec_state); }; with_block_3(); EndTest(); @@ -347,14 +404,12 @@ function with_block_4() { } listener_delegate = function(exec_state) { - CheckScopeChain([debug.ScopeType.Block, - debug.ScopeType.With, - debug.ScopeType.Block, + CheckScopeChain([debug.ScopeType.With, debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.Global], exec_state); - CheckScopeContent({a:2,b:1}, 1, exec_state); - CheckScopeContent({a:1,b:2}, 3, exec_state); + CheckScopeContent({a:2,b:1}, 0, exec_state); + CheckScopeContent({a:1,b:2}, 1, exec_state); }; with_block_4(); EndTest();