Commit ccd2cd8f authored by keuchel@chromium.org's avatar keuchel@chromium.org

Prune empty block scopes from scope tree

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
parent b7eb138e
......@@ -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;
......
......@@ -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;
}
}
......
......@@ -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()) {
......
......@@ -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
......
......@@ -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();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment