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
This commit is contained in:
parent
b7eb138eab
commit
ccd2cd8f64
@ -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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user