Provide a helper to generate multiple Lithium instructions for one Hydrogen instruction.

R=jkummerow@chromium.org, ulan@chromium.org

Review URL: https://codereview.chromium.org/296993002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21465 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7c55f645
...@@ -835,69 +835,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { ...@@ -835,69 +835,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
ASSERT(argument_count_ >= 0); ASSERT(argument_count_ >= 0);
if (instr != NULL) { if (instr != NULL) {
// Associate the hydrogen instruction first, since we may need it for AddInstruction(instr, current);
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below. }
instr->set_hydrogen_value(current);
current_instruction_ = old_current;
}
void LChunkBuilder::AddInstruction(LInstruction* instr,
HInstruction* hydrogen_val) {
// Associate the hydrogen instruction first, since we may need it for
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
instr->set_hydrogen_value(hydrogen_val);
#if DEBUG #if DEBUG
// Make sure that the lithium instruction has either no fixed register // Make sure that the lithium instruction has either no fixed register
// constraints in temps or the result OR no uses that are only used at // constraints in temps or the result OR no uses that are only used at
// start. If this invariant doesn't hold, the register allocator can decide // start. If this invariant doesn't hold, the register allocator can decide
// to insert a split of a range immediately before the instruction due to an // to insert a split of a range immediately before the instruction due to an
// already allocated register needing to be used for the instruction's fixed // already allocated register needing to be used for the instruction's fixed
// register constraint. In this case, The register allocator won't see an // register constraint. In this case, The register allocator won't see an
// interference between the split child and the use-at-start (it would if // interference between the split child and the use-at-start (it would if
// the it was just a plain use), so it is free to move the split child into // the it was just a plain use), so it is free to move the split child into
// the same register that is used for the use-at-start. // the same register that is used for the use-at-start.
// See https://code.google.com/p/chromium/issues/detail?id=201590 // See https://code.google.com/p/chromium/issues/detail?id=201590
if (!(instr->ClobbersRegisters() && if (!(instr->ClobbersRegisters() &&
instr->ClobbersDoubleRegisters(isolate()))) { instr->ClobbersDoubleRegisters(isolate()))) {
int fixed = 0; int fixed = 0;
int used_at_start = 0; int used_at_start = 0;
for (UseIterator it(instr); !it.Done(); it.Advance()) { for (UseIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current()); LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->IsUsedAtStart()) ++used_at_start; if (operand->IsUsedAtStart()) ++used_at_start;
} }
if (instr->Output() != NULL) { if (instr->Output() != NULL) {
if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
}
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
} }
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
}
#endif #endif
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr); instr = AssignPointerMap(instr);
} }
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
LInstruction* instruction_needing_environment = NULL;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
} }
chunk_->AddInstruction(instr, current_block_); LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
if (instr->IsCall()) { chunk_->AddInstruction(bailout, current_block_);
HValue* hydrogen_value_for_lazy_bailout = current; if (instruction_needing_environment != NULL) {
LInstruction* instruction_needing_environment = NULL; // Store the lazy deopt environment with the instruction if needed.
if (current->HasObservableSideEffects()) { // Right now it is only used for LInstanceOfKnownGlobal.
HSimulate* sim = HSimulate::cast(current->next()); instruction_needing_environment->
instruction_needing_environment = instr; SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
} }
} }
current_instruction_ = old_current;
} }
......
...@@ -2837,6 +2837,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase { ...@@ -2837,6 +2837,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
void VisitInstruction(HInstruction* current); void VisitInstruction(HInstruction* current);
void AddInstruction(LInstruction* instr, HInstruction* current);
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr); LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
......
...@@ -679,69 +679,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { ...@@ -679,69 +679,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
ASSERT(argument_count_ >= 0); ASSERT(argument_count_ >= 0);
if (instr != NULL) { if (instr != NULL) {
// Associate the hydrogen instruction first, since we may need it for AddInstruction(instr, current);
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below. }
instr->set_hydrogen_value(current);
current_instruction_ = old_current;
}
void LChunkBuilder::AddInstruction(LInstruction* instr,
HInstruction* hydrogen_val) {
// Associate the hydrogen instruction first, since we may need it for
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
instr->set_hydrogen_value(hydrogen_val);
#if DEBUG #if DEBUG
// Make sure that the lithium instruction has either no fixed register // Make sure that the lithium instruction has either no fixed register
// constraints in temps or the result OR no uses that are only used at // constraints in temps or the result OR no uses that are only used at
// start. If this invariant doesn't hold, the register allocator can decide // start. If this invariant doesn't hold, the register allocator can decide
// to insert a split of a range immediately before the instruction due to an // to insert a split of a range immediately before the instruction due to an
// already allocated register needing to be used for the instruction's fixed // already allocated register needing to be used for the instruction's fixed
// register constraint. In this case, the register allocator won't see an // register constraint. In this case, the register allocator won't see an
// interference between the split child and the use-at-start (it would if // interference between the split child and the use-at-start (it would if
// the it was just a plain use), so it is free to move the split child into // the it was just a plain use), so it is free to move the split child into
// the same register that is used for the use-at-start. // the same register that is used for the use-at-start.
// See https://code.google.com/p/chromium/issues/detail?id=201590 // See https://code.google.com/p/chromium/issues/detail?id=201590
if (!(instr->ClobbersRegisters() && if (!(instr->ClobbersRegisters() &&
instr->ClobbersDoubleRegisters(isolate()))) { instr->ClobbersDoubleRegisters(isolate()))) {
int fixed = 0; int fixed = 0;
int used_at_start = 0; int used_at_start = 0;
for (UseIterator it(instr); !it.Done(); it.Advance()) { for (UseIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current()); LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->IsUsedAtStart()) ++used_at_start; if (operand->IsUsedAtStart()) ++used_at_start;
} }
if (instr->Output() != NULL) { if (instr->Output() != NULL) {
if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
}
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
} }
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
}
#endif #endif
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr); instr = AssignPointerMap(instr);
} }
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
LInstruction* instruction_needing_environment = NULL;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
} }
chunk_->AddInstruction(instr, current_block_); LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
if (instr->IsCall()) { chunk_->AddInstruction(bailout, current_block_);
HValue* hydrogen_value_for_lazy_bailout = current; if (instruction_needing_environment != NULL) {
LInstruction* instruction_needing_environment = NULL; // Store the lazy deopt environment with the instruction if needed.
if (current->HasObservableSideEffects()) { // Right now it is only used for LInstanceOfKnownGlobal.
HSimulate* sim = HSimulate::cast(current->next()); instruction_needing_environment->
instruction_needing_environment = instr; SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
} }
} }
current_instruction_ = old_current;
} }
......
...@@ -3137,6 +3137,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase { ...@@ -3137,6 +3137,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
LInstruction* AssignEnvironment(LInstruction* instr); LInstruction* AssignEnvironment(LInstruction* instr);
void VisitInstruction(HInstruction* current); void VisitInstruction(HInstruction* current);
void AddInstruction(LInstruction* instr, HInstruction* current);
void DoBasicBlock(HBasicBlock* block); void DoBasicBlock(HBasicBlock* block);
int JSShiftAmountFromHConstant(HValue* constant) { int JSShiftAmountFromHConstant(HValue* constant) {
......
...@@ -889,69 +889,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { ...@@ -889,69 +889,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
ASSERT(argument_count_ >= 0); ASSERT(argument_count_ >= 0);
if (instr != NULL) { if (instr != NULL) {
// Associate the hydrogen instruction first, since we may need it for AddInstruction(instr, current);
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below. }
instr->set_hydrogen_value(current);
current_instruction_ = old_current;
}
void LChunkBuilder::AddInstruction(LInstruction* instr,
HInstruction* hydrogen_val) {
// Associate the hydrogen instruction first, since we may need it for
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
instr->set_hydrogen_value(hydrogen_val);
#if DEBUG #if DEBUG
// Make sure that the lithium instruction has either no fixed register // Make sure that the lithium instruction has either no fixed register
// constraints in temps or the result OR no uses that are only used at // constraints in temps or the result OR no uses that are only used at
// start. If this invariant doesn't hold, the register allocator can decide // start. If this invariant doesn't hold, the register allocator can decide
// to insert a split of a range immediately before the instruction due to an // to insert a split of a range immediately before the instruction due to an
// already allocated register needing to be used for the instruction's fixed // already allocated register needing to be used for the instruction's fixed
// register constraint. In this case, The register allocator won't see an // register constraint. In this case, The register allocator won't see an
// interference between the split child and the use-at-start (it would if // interference between the split child and the use-at-start (it would if
// the it was just a plain use), so it is free to move the split child into // the it was just a plain use), so it is free to move the split child into
// the same register that is used for the use-at-start. // the same register that is used for the use-at-start.
// See https://code.google.com/p/chromium/issues/detail?id=201590 // See https://code.google.com/p/chromium/issues/detail?id=201590
if (!(instr->ClobbersRegisters() && if (!(instr->ClobbersRegisters() &&
instr->ClobbersDoubleRegisters(isolate()))) { instr->ClobbersDoubleRegisters(isolate()))) {
int fixed = 0; int fixed = 0;
int used_at_start = 0; int used_at_start = 0;
for (UseIterator it(instr); !it.Done(); it.Advance()) { for (UseIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current()); LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->IsUsedAtStart()) ++used_at_start; if (operand->IsUsedAtStart()) ++used_at_start;
} }
if (instr->Output() != NULL) { if (instr->Output() != NULL) {
if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
}
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
} }
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
}
#endif #endif
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr); instr = AssignPointerMap(instr);
} }
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
LInstruction* instruction_needing_environment = NULL;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
} }
chunk_->AddInstruction(instr, current_block_); LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
if (instr->IsCall()) { chunk_->AddInstruction(bailout, current_block_);
HValue* hydrogen_value_for_lazy_bailout = current; if (instruction_needing_environment != NULL) {
LInstruction* instruction_needing_environment = NULL; // Store the lazy deopt environment with the instruction if needed.
if (current->HasObservableSideEffects()) { // Right now it is only used for LInstanceOfKnownGlobal.
HSimulate* sim = HSimulate::cast(current->next()); instruction_needing_environment->
instruction_needing_environment = instr; SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
} }
} }
current_instruction_ = old_current;
} }
......
...@@ -2831,6 +2831,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase { ...@@ -2831,6 +2831,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
void VisitInstruction(HInstruction* current); void VisitInstruction(HInstruction* current);
void AddInstruction(LInstruction* instr, HInstruction* current);
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr); LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
......
...@@ -843,69 +843,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { ...@@ -843,69 +843,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
ASSERT(argument_count_ >= 0); ASSERT(argument_count_ >= 0);
if (instr != NULL) { if (instr != NULL) {
// Associate the hydrogen instruction first, since we may need it for AddInstruction(instr, current);
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below. }
instr->set_hydrogen_value(current);
current_instruction_ = old_current;
}
void LChunkBuilder::AddInstruction(LInstruction* instr,
HInstruction* hydrogen_val) {
// Associate the hydrogen instruction first, since we may need it for
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
instr->set_hydrogen_value(hydrogen_val);
#if DEBUG #if DEBUG
// Make sure that the lithium instruction has either no fixed register // Make sure that the lithium instruction has either no fixed register
// constraints in temps or the result OR no uses that are only used at // constraints in temps or the result OR no uses that are only used at
// start. If this invariant doesn't hold, the register allocator can decide // start. If this invariant doesn't hold, the register allocator can decide
// to insert a split of a range immediately before the instruction due to an // to insert a split of a range immediately before the instruction due to an
// already allocated register needing to be used for the instruction's fixed // already allocated register needing to be used for the instruction's fixed
// register constraint. In this case, The register allocator won't see an // register constraint. In this case, The register allocator won't see an
// interference between the split child and the use-at-start (it would if // interference between the split child and the use-at-start (it would if
// the it was just a plain use), so it is free to move the split child into // the it was just a plain use), so it is free to move the split child into
// the same register that is used for the use-at-start. // the same register that is used for the use-at-start.
// See https://code.google.com/p/chromium/issues/detail?id=201590 // See https://code.google.com/p/chromium/issues/detail?id=201590
if (!(instr->ClobbersRegisters() && if (!(instr->ClobbersRegisters() &&
instr->ClobbersDoubleRegisters(isolate()))) { instr->ClobbersDoubleRegisters(isolate()))) {
int fixed = 0; int fixed = 0;
int used_at_start = 0; int used_at_start = 0;
for (UseIterator it(instr); !it.Done(); it.Advance()) { for (UseIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current()); LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->IsUsedAtStart()) ++used_at_start; if (operand->IsUsedAtStart()) ++used_at_start;
} }
if (instr->Output() != NULL) { if (instr->Output() != NULL) {
if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
}
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
} }
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
}
#endif #endif
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr); instr = AssignPointerMap(instr);
} }
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
LInstruction* instruction_needing_environment = NULL;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
} }
chunk_->AddInstruction(instr, current_block_); LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
if (instr->IsCall()) { chunk_->AddInstruction(bailout, current_block_);
HValue* hydrogen_value_for_lazy_bailout = current; if (instruction_needing_environment != NULL) {
LInstruction* instruction_needing_environment = NULL; // Store the lazy deopt environment with the instruction if needed.
if (current->HasObservableSideEffects()) { // Right now it is only used for LInstanceOfKnownGlobal.
HSimulate* sim = HSimulate::cast(current->next()); instruction_needing_environment->
instruction_needing_environment = instr; SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
} }
} }
current_instruction_ = old_current;
} }
......
...@@ -2792,6 +2792,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase { ...@@ -2792,6 +2792,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
void VisitInstruction(HInstruction* current); void VisitInstruction(HInstruction* current);
void AddInstruction(LInstruction* instr, HInstruction* current);
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
LInstruction* DoBit(Token::Value op, HBitwiseBinaryOperation* instr); LInstruction* DoBit(Token::Value op, HBitwiseBinaryOperation* instr);
......
...@@ -856,69 +856,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { ...@@ -856,69 +856,76 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
ASSERT(argument_count_ >= 0); ASSERT(argument_count_ >= 0);
if (instr != NULL) { if (instr != NULL) {
// Associate the hydrogen instruction first, since we may need it for AddInstruction(instr, current);
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below. }
instr->set_hydrogen_value(current);
current_instruction_ = old_current;
}
void LChunkBuilder::AddInstruction(LInstruction* instr,
HInstruction* hydrogen_val) {
// Associate the hydrogen instruction first, since we may need it for
// the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
instr->set_hydrogen_value(hydrogen_val);
#if DEBUG #if DEBUG
// Make sure that the lithium instruction has either no fixed register // Make sure that the lithium instruction has either no fixed register
// constraints in temps or the result OR no uses that are only used at // constraints in temps or the result OR no uses that are only used at
// start. If this invariant doesn't hold, the register allocator can decide // start. If this invariant doesn't hold, the register allocator can decide
// to insert a split of a range immediately before the instruction due to an // to insert a split of a range immediately before the instruction due to an
// already allocated register needing to be used for the instruction's fixed // already allocated register needing to be used for the instruction's fixed
// register constraint. In this case, The register allocator won't see an // register constraint. In this case, The register allocator won't see an
// interference between the split child and the use-at-start (it would if // interference between the split child and the use-at-start (it would if
// the it was just a plain use), so it is free to move the split child into // the it was just a plain use), so it is free to move the split child into
// the same register that is used for the use-at-start. // the same register that is used for the use-at-start.
// See https://code.google.com/p/chromium/issues/detail?id=201590 // See https://code.google.com/p/chromium/issues/detail?id=201590
if (!(instr->ClobbersRegisters() && if (!(instr->ClobbersRegisters() &&
instr->ClobbersDoubleRegisters(isolate()))) { instr->ClobbersDoubleRegisters(isolate()))) {
int fixed = 0; int fixed = 0;
int used_at_start = 0; int used_at_start = 0;
for (UseIterator it(instr); !it.Done(); it.Advance()) { for (UseIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current()); LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->IsUsedAtStart()) ++used_at_start; if (operand->IsUsedAtStart()) ++used_at_start;
} }
if (instr->Output() != NULL) { if (instr->Output() != NULL) {
if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
}
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
} }
for (TempIterator it(instr); !it.Done(); it.Advance()) {
LUnallocated* operand = LUnallocated::cast(it.Current());
if (operand->HasFixedPolicy()) ++fixed;
}
ASSERT(fixed == 0 || used_at_start == 0);
}
#endif #endif
if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
instr = AssignPointerMap(instr); instr = AssignPointerMap(instr);
} }
if (FLAG_stress_environments && !instr->HasEnvironment()) { if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr); instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
LInstruction* instruction_needing_environment = NULL;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
} }
chunk_->AddInstruction(instr, current_block_); LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
if (instr->IsCall()) { chunk_->AddInstruction(bailout, current_block_);
HValue* hydrogen_value_for_lazy_bailout = current; if (instruction_needing_environment != NULL) {
LInstruction* instruction_needing_environment = NULL; // Store the lazy deopt environment with the instruction if needed.
if (current->HasObservableSideEffects()) { // Right now it is only used for LInstanceOfKnownGlobal.
HSimulate* sim = HSimulate::cast(current->next()); instruction_needing_environment->
instruction_needing_environment = instr; SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
} }
} }
current_instruction_ = old_current;
} }
......
...@@ -2806,6 +2806,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase { ...@@ -2806,6 +2806,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
void VisitInstruction(HInstruction* current); void VisitInstruction(HInstruction* current);
void AddInstruction(LInstruction* instr, HInstruction* current);
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr); LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment