Fix issue 268 by explicitly calling Unuse (to deallocate all contained

virtual frames) on zone-allocated jump targets.  These include jump
targets in AST nodes and the entry and exit targets of deferred code.

See http://code.google.com/p/v8/issues/detail?id=268

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1486 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2009-03-11 10:25:48 +00:00
parent 1094cfe1b6
commit 82df32b78c
6 changed files with 74 additions and 30 deletions

View File

@ -284,7 +284,11 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
DeleteFrame(); DeleteFrame();
// Process any deferred code using the register allocator. // Process any deferred code using the register allocator.
ProcessDeferred(); if (HasStackOverflow()) {
ClearDeferred();
} else {
ProcessDeferred();
}
allocator_ = NULL; allocator_ = NULL;
scope_ = NULL; scope_ = NULL;
@ -1133,6 +1137,7 @@ void CodeGenerator::VisitBlock(Block* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
node->break_target()->Unuse();
ASSERT(!has_valid_frame() || frame_->height() == original_height); ASSERT(!has_valid_frame() || frame_->height() == original_height);
} }
@ -1594,6 +1599,7 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
node->break_target()->Unuse();
ASSERT(!has_valid_frame() || frame_->height() == original_height); ASSERT(!has_valid_frame() || frame_->height() == original_height);
} }
@ -1781,6 +1787,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
node->continue_target()->Unuse();
node->break_target()->Unuse();
ASSERT(!has_valid_frame() || frame_->height() == original_height); ASSERT(!has_valid_frame() || frame_->height() == original_height);
} }
@ -1971,6 +1979,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// Exit. // Exit.
exit.Bind(); exit.Bind();
node->continue_target()->Unuse();
node->break_target()->Unuse();
ASSERT(frame_->height() == original_height); ASSERT(frame_->height() == original_height);
} }

View File

@ -195,6 +195,8 @@ class CodeGenerator: public AstVisitor {
// Accessors // Accessors
Scope* scope() const { return scope_; } Scope* scope() const { return scope_; }
// Clearing and generating deferred code.
void ClearDeferred();
void ProcessDeferred(); void ProcessDeferred();
bool is_eval() { return is_eval_; } bool is_eval() { return is_eval_; }

View File

@ -307,7 +307,11 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
DeleteFrame(); DeleteFrame();
// Process any deferred code using the register allocator. // Process any deferred code using the register allocator.
ProcessDeferred(); if (HasStackOverflow()) {
ClearDeferred();
} else {
ProcessDeferred();
}
// There is no need to delete the register allocator, it is a // There is no need to delete the register allocator, it is a
// stack-allocated local. // stack-allocated local.
@ -1567,6 +1571,7 @@ void CodeGenerator::VisitBlock(Block* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
node->break_target()->Unuse();
} }
@ -2094,37 +2099,39 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
// There are two ways to reach the body: from the corresponding // There are two ways to reach the body: from the corresponding
// test or as the fall through of the previous body. // test or as the fall through of the previous body.
if (!clause->body_target()->is_linked() && !has_valid_frame()) { if (clause->body_target()->is_linked() || has_valid_frame()) {
// If we have neither, skip this body. if (clause->body_target()->is_linked()) {
continue; if (has_valid_frame()) {
} else if (clause->body_target()->is_linked() && has_valid_frame()) { // If we have both a jump to the test and a fall through, put
// If we have both, put a jump on the fall through path to avoid // a jump on the fall through path to avoid the dropping of
// the dropping of the switch value on the test path. The // the switch value on the test path. The exception is the
// exception is the default which has already had the switch // default which has already had the switch value dropped.
// value dropped. if (clause->is_default()) {
if (clause->is_default()) { clause->body_target()->Bind();
clause->body_target()->Bind(); } else {
JumpTarget body(this);
body.Jump();
clause->body_target()->Bind();
frame_->Drop();
body.Bind();
}
} else {
// No fall through to worry about.
clause->body_target()->Bind();
if (!clause->is_default()) {
frame_->Drop();
}
}
} else { } else {
JumpTarget body(this); // Otherwise, we have only fall through.
body.Jump(); ASSERT(has_valid_frame());
clause->body_target()->Bind();
frame_->Drop();
body.Bind();
} }
} else if (clause->body_target()->is_linked()) {
// No fall through to worry about.
clause->body_target()->Bind();
if (!clause->is_default()) {
frame_->Drop();
}
} else {
// Otherwise, we have only fall through.
ASSERT(has_valid_frame());
}
// We are now prepared to compile the body. // We are now prepared to compile the body.
Comment cmnt(masm_, "[ Case body"); Comment cmnt(masm_, "[ Case body");
VisitStatements(clause->statements()); VisitStatements(clause->statements());
}
clause->body_target()->Unuse();
} }
// We may not have a valid frame here so bind the break target only // We may not have a valid frame here so bind the break target only
@ -2132,6 +2139,7 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
if (node->break_target()->is_linked()) { if (node->break_target()->is_linked()) {
node->break_target()->Bind(); node->break_target()->Bind();
} }
node->break_target()->Unuse();
} }
@ -2452,6 +2460,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
} }
DecrementLoopNesting(); DecrementLoopNesting();
node->continue_target()->Unuse();
node->break_target()->Unuse();
} }
@ -2636,6 +2646,9 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// Exit. // Exit.
exit.Bind(); exit.Bind();
node->continue_target()->Unuse();
node->break_target()->Unuse();
} }

View File

@ -340,6 +340,8 @@ class CodeGenerator: public AstVisitor {
// Accessors // Accessors
Scope* scope() const { return scope_; } Scope* scope() const { return scope_; }
// Clearing and generating deferred code.
void ClearDeferred();
void ProcessDeferred(); void ProcessDeferred();
bool is_eval() { return is_eval_; } bool is_eval() { return is_eval_; }

View File

@ -53,6 +53,13 @@ DeferredCode::DeferredCode(CodeGenerator* generator)
} }
void CodeGenerator::ClearDeferred() {
for (int i = 0; i < deferred_.length(); i++) {
deferred_[i]->Clear();
}
}
void CodeGenerator::ProcessDeferred() { void CodeGenerator::ProcessDeferred() {
while (!deferred_.is_empty()) { while (!deferred_.is_empty()) {
DeferredCode* code = deferred_.RemoveLast(); DeferredCode* code = deferred_.RemoveLast();
@ -66,6 +73,7 @@ void CodeGenerator::ProcessDeferred() {
Comment cmnt(masm, code->comment()); Comment cmnt(masm, code->comment());
code->Generate(); code->Generate();
ASSERT(code->enter()->is_bound()); ASSERT(code->enter()->is_bound());
code->Clear();
} }
} }

View File

@ -52,6 +52,7 @@
// CodeGenerator::CodeGenerator // CodeGenerator::CodeGenerator
// CodeGenerator::~CodeGenerator // CodeGenerator::~CodeGenerator
// CodeGenerator::ProcessDeferred // CodeGenerator::ProcessDeferred
// CodeGenerator::ClearDeferred
// CodeGenerator::GenCode // CodeGenerator::GenCode
// CodeGenerator::BuildBoilerplate // CodeGenerator::BuildBoilerplate
// CodeGenerator::ComputeCallInitialize // CodeGenerator::ComputeCallInitialize
@ -92,6 +93,14 @@ class DeferredCode: public ZoneObject {
virtual void Generate() = 0; virtual void Generate() = 0;
// Unuse the entry and exit targets, deallocating all virtual frames
// held by them. It will be impossible to emit a (correct) jump
// into or out of the deferred code after clearing.
void Clear() {
enter_.Unuse();
exit_.Unuse();
}
MacroAssembler* masm() const { return masm_; } MacroAssembler* masm() const { return masm_; }
CodeGenerator* generator() const { return generator_; } CodeGenerator* generator() const { return generator_; }