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:
parent
1094cfe1b6
commit
82df32b78c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_; }
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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_; }
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_; }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user