Change the handling of stack check on backward branches

The hydrogen stack check instruction is now added to each loop and the stack check handling on the back edge has been removed.

This change causes regression on small tight loops as the stack check is now at the top of the loop instead of at the bottom, and that requires one additional unconditional jump per loop iteration. However the reason for this change is to avoid worse regressions for upcoming changes to correctly support debugger break in optimized code.

R=fschneider@chromium.org

BUG=none
TEST=none

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8428 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
sgjesse@chromium.org 2011-06-27 12:12:27 +00:00
parent b7850c06d1
commit 54d6072332
15 changed files with 232 additions and 207 deletions

View File

@ -433,8 +433,7 @@ void LChunk::MarkEmptyBlocks() {
LLabel* label = LLabel::cast(first_instr);
if (last_instr->IsGoto()) {
LGoto* goto_instr = LGoto::cast(last_instr);
if (!goto_instr->include_stack_check() &&
label->IsRedundant() &&
if (label->IsRedundant() &&
!label->is_loop_header()) {
bool can_eliminate = true;
for (int i = first + 1; i < last && can_eliminate; ++i) {
@ -1043,10 +1042,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
LInstruction* result = new LGoto(instr->FirstSuccessor()->block_id(),
instr->include_stack_check());
if (instr->include_stack_check()) result = AssignPointerMap(result);
return result;
return new LGoto(instr->FirstSuccessor()->block_id());
}
@ -2207,7 +2203,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
return MarkAsCall(new LStackCheck, instr);
if (instr->is_function_entry()) {
return MarkAsCall(new LStackCheck, instr);
} else {
ASSERT(instr->is_backwards_branch());
return AssignEnvironment(AssignPointerMap(new LStackCheck));
}
}

View File

@ -371,19 +371,16 @@ class LInstructionGap: public LGap {
class LGoto: public LTemplateInstruction<0, 0, 0> {
public:
LGoto(int block_id, bool include_stack_check = false)
: block_id_(block_id), include_stack_check_(include_stack_check) { }
explicit LGoto(int block_id) : block_id_(block_id) { }
DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int block_id() const { return block_id_; }
bool include_stack_check() const { return include_stack_check_; }
private:
int block_id_;
bool include_stack_check_;
};
@ -2070,6 +2067,12 @@ class LOsrEntry: public LTemplateInstruction<0, 0, 0> {
class LStackCheck: public LTemplateInstruction<0, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
DECLARE_HYDROGEN_ACCESSOR(StackCheck)
Label* done_label() { return &done_label_; }
private:
Label done_label_;
};

View File

@ -1589,45 +1589,17 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
void LCodeGen::EmitGoto(int block) {
block = chunk_->LookupDestination(block);
int next_block = GetNextEmittedBlock(current_block_);
if (block != next_block) {
// Perform stack overflow check if this goto needs it before jumping.
if (deferred_stack_check != NULL) {
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip));
__ b(hs, chunk_->GetAssemblyLabel(block));
__ jmp(deferred_stack_check->entry());
deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
} else {
__ jmp(chunk_->GetAssemblyLabel(block));
}
__ jmp(chunk_->GetAssemblyLabel(block));
}
}
void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
}
void LCodeGen::DoGoto(LGoto* instr) {
class DeferredStackCheck: public LDeferredCode {
public:
DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
private:
LGoto* instr_;
};
DeferredStackCheck* deferred = NULL;
if (instr->include_stack_check()) {
deferred = new DeferredStackCheck(this, instr);
}
EmitGoto(instr->block_id(), deferred);
EmitGoto(instr->block_id());
}
@ -4575,15 +4547,42 @@ void LCodeGen::DoIn(LIn* instr) {
}
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
}
void LCodeGen::DoStackCheck(LStackCheck* instr) {
// Perform stack overflow check.
Label ok;
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip));
__ b(hs, &ok);
StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ bind(&ok);
class DeferredStackCheck: public LDeferredCode {
public:
DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
private:
LStackCheck* instr_;
};
if (instr->hydrogen()->is_function_entry()) {
// Perform stack overflow check.
Label done;
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip));
__ b(hs, &done);
StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ bind(&done);
} else {
ASSERT(instr->hydrogen()->is_backwards_branch());
// Perform stack overflow check if this goto needs it before jumping.
DeferredStackCheck* deferred_stack_check =
new DeferredStackCheck(this, instr);
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip));
__ b(lo, deferred_stack_check->entry());
__ bind(instr->done_label());
deferred_stack_check->SetExit(instr->done_label());
}
}

View File

@ -108,7 +108,7 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredNumberTagI(LNumberTagI* instr);
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
@ -261,7 +261,7 @@ class LCodeGen BASE_EMBEDDED {
}
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
void EmitGoto(int block);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input,

View File

@ -894,24 +894,15 @@ class HDeoptimize: public HControlInstruction {
class HGoto: public HTemplateControlInstruction<1, 0> {
public:
explicit HGoto(HBasicBlock* target)
: include_stack_check_(false) {
explicit HGoto(HBasicBlock* target) {
SetSuccessorAt(0, target);
}
void set_include_stack_check(bool include_stack_check) {
include_stack_check_ = include_stack_check;
}
bool include_stack_check() const { return include_stack_check_; }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::None();
}
DECLARE_CONCRETE_INSTRUCTION(Goto)
private:
bool include_stack_check_;
};
@ -1256,13 +1247,32 @@ class HSimulate: public HInstruction {
class HStackCheck: public HTemplateInstruction<0> {
public:
HStackCheck() { }
enum Type {
kFunctionEntry,
kBackwardsBranch
};
explicit HStackCheck(Type type) : type_(type) { }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::None();
}
void Eliminate() {
// The stack check eliminator might try to eliminate the same stack
// check instruction multiple times.
if (IsLinked()) {
DeleteFromGraph();
}
}
bool is_function_entry() { return type_ == kFunctionEntry; }
bool is_backwards_branch() { return type_ == kBackwardsBranch; }
DECLARE_CONCRETE_INSTRUCTION(StackCheck)
private:
Type type_;
};

View File

@ -163,14 +163,13 @@ void HBasicBlock::Finish(HControlInstruction* end) {
}
void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
void HBasicBlock::Goto(HBasicBlock* block) {
if (block->IsInlineReturnTarget()) {
AddInstruction(new(zone()) HLeaveInlined);
last_environment_ = last_environment()->outer();
}
AddSimulate(AstNode::kNoNumber);
HGoto* instr = new(zone()) HGoto(block);
instr->set_include_stack_check(include_stack_check);
Finish(instr);
}
@ -576,7 +575,7 @@ HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement,
HBasicBlock* body_exit,
HBasicBlock* loop_successor,
HBasicBlock* break_block) {
if (body_exit != NULL) body_exit->Goto(loop_entry, true);
if (body_exit != NULL) body_exit->Goto(loop_entry);
loop_entry->PostProcessLoopHeader(statement);
if (break_block != NULL) {
if (loop_successor != NULL) loop_successor->Goto(break_block);
@ -1234,8 +1233,6 @@ class HStackCheckEliminator BASE_EMBEDDED {
void Process();
private:
void RemoveStackCheck(HBasicBlock* block);
HGraph* graph_;
};
@ -1254,7 +1251,7 @@ void HStackCheckEliminator::Process() {
HInstruction* instr = dominator->first();
while (instr != NULL) {
if (instr->IsCall()) {
RemoveStackCheck(back_edge);
block->loop_information()->stack_check()->Eliminate();
break;
}
instr = instr->next();
@ -1271,18 +1268,6 @@ void HStackCheckEliminator::Process() {
}
void HStackCheckEliminator::RemoveStackCheck(HBasicBlock* block) {
HInstruction* instr = block->first();
while (instr != NULL) {
if (instr->IsGoto()) {
HGoto::cast(instr)->set_include_stack_check(false);
return;
}
instr = instr->next();
}
}
// Simple sparse set with O(1) add, contains, and clear.
class SparseSet {
public:
@ -2136,8 +2121,8 @@ void TestContext::BuildBranch(HValue* value) {
HTest* test = new(zone()) HTest(value, empty_true, empty_false);
builder->current_block()->Finish(test);
empty_true->Goto(if_true(), false);
empty_false->Goto(if_false(), false);
empty_true->Goto(if_true());
empty_false->Goto(if_false());
builder->set_current_block(NULL);
}
@ -2229,7 +2214,7 @@ HGraph* HGraphBuilder::CreateGraph() {
}
SetupScope(scope);
VisitDeclarations(scope->declarations());
AddInstruction(new(zone()) HStackCheck());
AddInstruction(new(zone()) HStackCheck(HStackCheck::kFunctionEntry));
// Add an edge to the body entry. This is warty: the graph's start
// environment will be used by the Lithium translation as the initial
@ -2567,7 +2552,7 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
test->if_false());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
current_block()->Goto(function_return(), false);
current_block()->Goto(function_return());
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
@ -2758,6 +2743,19 @@ void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
}
void HGraphBuilder::VisitLoopBody(Statement* body,
HBasicBlock* loop_entry,
BreakAndContinueInfo* break_info) {
BreakAndContinueScope push(break_info, this);
HStackCheck* stack_check =
new(zone()) HStackCheck(HStackCheck::kBackwardsBranch);
AddInstruction(stack_check);
ASSERT(loop_entry->IsLoopHeader());
loop_entry->loop_information()->set_stack_check(stack_check);
CHECK_BAILOUT(Visit(body));
}
void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@ -2765,13 +2763,11 @@ void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
ASSERT(current_block() != NULL);
PreProcessOsrEntry(stmt);
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
current_block()->Goto(loop_entry, false);
current_block()->Goto(loop_entry);
set_current_block(loop_entry);
BreakAndContinueInfo break_info(stmt);
{ BreakAndContinueScope push(&break_info, this);
CHECK_BAILOUT(Visit(stmt->body()));
}
CHECK_BAILOUT(VisitLoopBody(stmt->body(), loop_entry, &break_info));
HBasicBlock* body_exit =
JoinContinue(stmt, current_block(), break_info.continue_block());
HBasicBlock* loop_successor = NULL;
@ -2809,7 +2805,7 @@ void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
ASSERT(current_block() != NULL);
PreProcessOsrEntry(stmt);
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
current_block()->Goto(loop_entry, false);
current_block()->Goto(loop_entry);
set_current_block(loop_entry);
// If the condition is constant true, do not generate a branch.
@ -2832,7 +2828,7 @@ void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
BreakAndContinueInfo break_info(stmt);
if (current_block() != NULL) {
BreakAndContinueScope push(&break_info, this);
CHECK_BAILOUT(Visit(stmt->body()));
CHECK_BAILOUT(VisitLoopBody(stmt->body(), loop_entry, &break_info));
}
HBasicBlock* body_exit =
JoinContinue(stmt, current_block(), break_info.continue_block());
@ -2855,7 +2851,7 @@ void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
ASSERT(current_block() != NULL);
PreProcessOsrEntry(stmt);
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
current_block()->Goto(loop_entry, false);
current_block()->Goto(loop_entry);
set_current_block(loop_entry);
HBasicBlock* loop_successor = NULL;
@ -2877,7 +2873,7 @@ void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
BreakAndContinueInfo break_info(stmt);
if (current_block() != NULL) {
BreakAndContinueScope push(&break_info, this);
CHECK_BAILOUT(Visit(stmt->body()));
CHECK_BAILOUT(VisitLoopBody(stmt->body(), loop_entry, &break_info));
}
HBasicBlock* body_exit =
JoinContinue(stmt, current_block(), break_info.continue_block());
@ -4486,7 +4482,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
ASSERT(function_return() != NULL);
ASSERT(call_context()->IsEffect() || call_context()->IsValue());
if (call_context()->IsEffect()) {
current_block()->Goto(function_return(), false);
current_block()->Goto(function_return());
} else {
current_block()->AddLeaveInlined(undefined, function_return());
}
@ -4501,8 +4497,8 @@ bool HGraphBuilder::TryInline(Call* expr) {
HTest* test = new(zone()) HTest(undefined, empty_true, empty_false);
current_block()->Finish(test);
empty_true->Goto(inlined_test_context()->if_true(), false);
empty_false->Goto(inlined_test_context()->if_false(), false);
empty_true->Goto(inlined_test_context()->if_true());
empty_false->Goto(inlined_test_context()->if_false());
}
}
@ -4519,12 +4515,12 @@ bool HGraphBuilder::TryInline(Call* expr) {
if (if_true->HasPredecessor()) {
if_true->SetJoinId(expr->id());
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
if_true->Goto(true_target, false);
if_true->Goto(true_target);
}
if (if_false->HasPredecessor()) {
if_false->SetJoinId(expr->id());
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
if_false->Goto(false_target, false);
if_false->Goto(false_target);
}
set_current_block(NULL);

View File

@ -120,7 +120,7 @@ class HBasicBlock: public ZoneObject {
void Finish(HControlInstruction* last);
void FinishExit(HControlInstruction* instruction);
void Goto(HBasicBlock* block, bool include_stack_check = false);
void Goto(HBasicBlock* block);
int PredecessorIndexOf(HBasicBlock* predecessor) const;
void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
@ -185,7 +185,10 @@ class HBasicBlock: public ZoneObject {
class HLoopInformation: public ZoneObject {
public:
explicit HLoopInformation(HBasicBlock* loop_header)
: back_edges_(4), loop_header_(loop_header), blocks_(8) {
: back_edges_(4),
loop_header_(loop_header),
blocks_(8),
stack_check_(NULL) {
blocks_.Add(loop_header);
}
virtual ~HLoopInformation() {}
@ -196,12 +199,18 @@ class HLoopInformation: public ZoneObject {
HBasicBlock* GetLastBackEdge() const;
void RegisterBackEdge(HBasicBlock* block);
HStackCheck* stack_check() const { return stack_check_; }
void set_stack_check(HStackCheck* stack_check) {
stack_check_ = stack_check;
}
private:
void AddBlock(HBasicBlock* block);
ZoneList<HBasicBlock*> back_edges_;
HBasicBlock* loop_header_;
ZoneList<HBasicBlock*> blocks_;
HStackCheck* stack_check_;
};
@ -771,6 +780,9 @@ class HGraphBuilder: public AstVisitor {
void PreProcessOsrEntry(IterationStatement* statement);
// True iff. we are compiling for OSR and the statement is the entry.
bool HasOsrEntryAt(IterationStatement* statement);
void VisitLoopBody(Statement* body,
HBasicBlock* loop_entry,
BreakAndContinueInfo* break_info);
HBasicBlock* CreateJoin(HBasicBlock* first,
HBasicBlock* second,

View File

@ -1423,45 +1423,17 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
void LCodeGen::EmitGoto(int block) {
block = chunk_->LookupDestination(block);
int next_block = GetNextEmittedBlock(current_block_);
if (block != next_block) {
// Perform stack overflow check if this goto needs it before jumping.
if (deferred_stack_check != NULL) {
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, chunk_->GetAssemblyLabel(block));
__ jmp(deferred_stack_check->entry());
deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
} else {
__ jmp(chunk_->GetAssemblyLabel(block));
}
__ jmp(chunk_->GetAssemblyLabel(block));
}
}
void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
PushSafepointRegistersScope scope(this);
CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
}
void LCodeGen::DoGoto(LGoto* instr) {
class DeferredStackCheck: public LDeferredCode {
public:
DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
private:
LGoto* instr_;
};
DeferredStackCheck* deferred = NULL;
if (instr->include_stack_check()) {
deferred = new DeferredStackCheck(this, instr);
}
EmitGoto(instr->block_id(), deferred);
EmitGoto(instr->block_id());
}
@ -4410,17 +4382,45 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
}
void LCodeGen::DoStackCheck(LStackCheck* instr) {
// Perform stack overflow check.
Label done;
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &done, Label::kNear);
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
PushSafepointRegistersScope scope(this);
CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
}
StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
__ bind(&done);
void LCodeGen::DoStackCheck(LStackCheck* instr) {
class DeferredStackCheck: public LDeferredCode {
public:
DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
private:
LStackCheck* instr_;
};
if (instr->hydrogen()->is_function_entry()) {
// Perform stack overflow check.
Label done;
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &done, Label::kNear);
StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
__ bind(&done);
} else {
ASSERT(instr->hydrogen()->is_backwards_branch());
// Perform stack overflow check if this goto needs it before jumping.
DeferredStackCheck* deferred_stack_check =
new DeferredStackCheck(this, instr);
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(below, deferred_stack_check->entry());
__ bind(instr->done_label());
deferred_stack_check->SetExit(instr->done_label());
}
}

View File

@ -97,7 +97,7 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredNumberTagI(LNumberTagI* instr);
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
@ -258,7 +258,7 @@ class LCodeGen BASE_EMBEDDED {
void RecordPosition(int position);
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
void EmitGoto(int block);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input,

View File

@ -391,8 +391,7 @@ void LChunk::MarkEmptyBlocks() {
LLabel* label = LLabel::cast(first_instr);
if (last_instr->IsGoto()) {
LGoto* goto_instr = LGoto::cast(last_instr);
if (!goto_instr->include_stack_check() &&
label->IsRedundant() &&
if (label->IsRedundant() &&
!label->is_loop_header()) {
bool can_eliminate = true;
for (int i = first + 1; i < last && can_eliminate; ++i) {
@ -1038,11 +1037,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
LGoto* result = new LGoto(instr->FirstSuccessor()->block_id(),
instr->include_stack_check());
return (instr->include_stack_check())
? AssignPointerMap(result)
: result;
return new LGoto(instr->FirstSuccessor()->block_id());
}
@ -2258,7 +2253,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
return MarkAsCall(new LStackCheck, instr);
if (instr->is_function_entry()) {
return MarkAsCall(new LStackCheck, instr);
} else {
ASSERT(instr->is_backwards_branch());
return AssignEnvironment(AssignPointerMap(new LStackCheck));
}
}

View File

@ -365,19 +365,16 @@ class LInstructionGap: public LGap {
class LGoto: public LTemplateInstruction<0, 0, 0> {
public:
LGoto(int block_id, bool include_stack_check = false)
: block_id_(block_id), include_stack_check_(include_stack_check) { }
explicit LGoto(int block_id) : block_id_(block_id) { }
DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int block_id() const { return block_id_; }
bool include_stack_check() const { return include_stack_check_; }
private:
int block_id_;
bool include_stack_check_;
};
@ -2109,6 +2106,12 @@ class LOsrEntry: public LTemplateInstruction<0, 0, 0> {
class LStackCheck: public LTemplateInstruction<0, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
DECLARE_HYDROGEN_ACCESSOR(StackCheck)
Label* done_label() { return &done_label_; }
private:
Label done_label_;
};

View File

@ -1425,44 +1425,17 @@ void LCodeGen::DoBranch(LBranch* instr) {
}
void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
void LCodeGen::EmitGoto(int block) {
block = chunk_->LookupDestination(block);
int next_block = GetNextEmittedBlock(current_block_);
if (block != next_block) {
// Perform stack overflow check if this goto needs it before jumping.
if (deferred_stack_check != NULL) {
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(above_equal, chunk_->GetAssemblyLabel(block));
__ jmp(deferred_stack_check->entry());
deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
} else {
__ jmp(chunk_->GetAssemblyLabel(block));
}
__ jmp(chunk_->GetAssemblyLabel(block));
}
}
void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
PushSafepointRegistersScope scope(this);
CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
}
void LCodeGen::DoGoto(LGoto* instr) {
class DeferredStackCheck: public LDeferredCode {
public:
DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
private:
LGoto* instr_;
};
DeferredStackCheck* deferred = NULL;
if (instr->include_stack_check()) {
deferred = new DeferredStackCheck(this, instr);
}
EmitGoto(instr->block_id(), deferred);
EmitGoto(instr->block_id());
}
@ -4265,15 +4238,40 @@ void LCodeGen::DoIn(LIn* instr) {
}
void LCodeGen::DoStackCheck(LStackCheck* instr) {
// Perform stack overflow check.
Label done;
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(above_equal, &done, Label::kNear);
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
PushSafepointRegistersScope scope(this);
CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
}
StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ bind(&done);
void LCodeGen::DoStackCheck(LStackCheck* instr) {
class DeferredStackCheck: public LDeferredCode {
public:
DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
private:
LStackCheck* instr_;
};
if (instr->hydrogen()->is_function_entry()) {
// Perform stack overflow check.
Label done;
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(above_equal, &done, Label::kNear);
StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ bind(&done);
} else {
ASSERT(instr->hydrogen()->is_backwards_branch());
// Perform stack overflow check if this goto needs it before jumping.
DeferredStackCheck* deferred_stack_check =
new DeferredStackCheck(this, instr);
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(below, deferred_stack_check->entry());
__ bind(instr->done_label());
deferred_stack_check->SetExit(instr->done_label());
}
}

View File

@ -94,7 +94,7 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredNumberTagD(LNumberTagD* instr);
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
@ -247,7 +247,7 @@ class LCodeGen BASE_EMBEDDED {
}
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
void EmitGoto(int block);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input,

View File

@ -390,8 +390,7 @@ void LChunk::MarkEmptyBlocks() {
LLabel* label = LLabel::cast(first_instr);
if (last_instr->IsGoto()) {
LGoto* goto_instr = LGoto::cast(last_instr);
if (!goto_instr->include_stack_check() &&
label->IsRedundant() &&
if (label->IsRedundant() &&
!label->is_loop_header()) {
bool can_eliminate = true;
for (int i = first + 1; i < last && can_eliminate; ++i) {
@ -1038,11 +1037,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
LGoto* result = new LGoto(instr->FirstSuccessor()->block_id(),
instr->include_stack_check());
return (instr->include_stack_check())
? AssignPointerMap(result)
: result;
return new LGoto(instr->FirstSuccessor()->block_id());
}
@ -2199,7 +2194,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
return MarkAsCall(new LStackCheck, instr);
if (instr->is_function_entry()) {
return MarkAsCall(new LStackCheck, instr);
} else {
ASSERT(instr->is_backwards_branch());
return AssignEnvironment(AssignPointerMap(new LStackCheck));
}
}

View File

@ -372,19 +372,16 @@ class LInstructionGap: public LGap {
class LGoto: public LTemplateInstruction<0, 0, 0> {
public:
LGoto(int block_id, bool include_stack_check = false)
: block_id_(block_id), include_stack_check_(include_stack_check) { }
explicit LGoto(int block_id) : block_id_(block_id) { }
DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
virtual void PrintDataTo(StringStream* stream);
virtual bool IsControl() const { return true; }
int block_id() const { return block_id_; }
bool include_stack_check() const { return include_stack_check_; }
private:
int block_id_;
bool include_stack_check_;
};
@ -2063,6 +2060,12 @@ class LOsrEntry: public LTemplateInstruction<0, 0, 0> {
class LStackCheck: public LTemplateInstruction<0, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
DECLARE_HYDROGEN_ACCESSOR(StackCheck)
Label* done_label() { return &done_label_; }
private:
Label done_label_;
};