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:
parent
b7850c06d1
commit
54d6072332
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user