Prune empty block scopes from scope tree
authorkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Sep 2011 12:43:28 +0000 (12:43 +0000)
committerkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Sep 2011 12:43:28 +0000 (12:43 +0000)
BUG=
TEST=

Review URL: http://codereview.chromium.org/7825006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9117 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/heap.h
src/parser.cc
src/scopes.cc
src/scopes.h
test/mjsunit/harmony/debug-blockscopes.js

index 0f69fab3910011d13b3fa9a88e0b3637581b361f..8eb42d3a31068b8f9be4aeaf057ab441ea7eaece 100644 (file)
@@ -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;
index d685b8a34453d4e470f5df9737e0d456b5f19fe3..a863165b015ac78d883a88f5ffc5bfab5e727e51 100644 (file)
@@ -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);
+  top_scope_ = saved_scope;
 
-  // Create exit block.
-  Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
-  exit->AddStatement(new(zone()) ExitContextStatement());
+  block_scope = block_scope->FinalizeBlockScope();
+  body->set_block_scope(block_scope);
 
-  // Create a try-finally statement.
-  TryFinallyStatement* try_finally =
-      new(zone()) TryFinallyStatement(body, exit);
-  try_finally->set_escaping_targets(collector.targets());
-  top_scope_ = saved_scope;
+  if (block_scope != NULL) {
+    // Create exit block.
+    Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
+    exit->AddStatement(new(zone()) ExitContextStatement());
 
-  // Create a result block.
-  Block* result = new(zone()) Block(isolate(), NULL, 1, false);
-  result->AddStatement(try_finally);
-  return result;
+    // 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;
+  }
 }
 
 
index b2958db60fbc20d5d7689bfcb4aca8adf50ca2c6..15634d09514d47daa128dc24f9d3ecf05e15587d 100644 (file)
@@ -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<String> name) {
   Variable* result = variables_.Lookup(name);
   if (result != NULL || scope_info_.is_null()) {
index a01d9c7d472b5c2b1005d158c5efed6088c6af0e..d18c6bc2740a70f0eb0eb92d4c1aa392360b5e32 100644 (file)
@@ -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
 
index e0df71b2dfe9a6df1898b3d0446a889934312e0b..d02c9f6a8e9257e980faa52a9727ad509cc4baa2 100644 (file)
@@ -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();