Index: src/compiler/bytecode-graph-builder.cc |
diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc |
index 558ef12684b5daf93e59d5eb2ab08d9cb469bac1..80bf950940833a1f4a8c4f6348082e459dcef38a 100644 |
--- a/src/compiler/bytecode-graph-builder.cc |
+++ b/src/compiler/bytecode-graph-builder.cc |
@@ -35,6 +35,7 @@ |
Node* LookupAccumulator() const; |
Node* LookupRegister(interpreter::Register the_register) const; |
+ void MarkAllRegistersLive(); |
void BindAccumulator(Node* node, |
FrameStateAttachmentMode mode = kDontAttachFrameState); |
@@ -55,7 +56,7 @@ |
// Preserve a checkpoint of the environment for the IR graph. Any |
// further mutation of the environment will not affect checkpoints. |
Node* Checkpoint(BailoutId bytecode_offset, OutputFrameStateCombine combine, |
- bool owner_has_exception, const BitVector* liveness); |
+ bool owner_has_exception); |
// Control dependency tracked by this environment. |
Node* GetControlDependency() const { return control_dependency_; } |
@@ -75,20 +76,21 @@ |
void PrepareForLoopExit(Node* loop); |
private: |
- explicit Environment(const Environment* copy); |
+ Environment(const Environment* copy, LivenessAnalyzerBlock* liveness_block); |
void PrepareForLoop(); |
- bool StateValuesRequireUpdate(Node** state_values, Node** values, int count); |
- void UpdateStateValues(Node** state_values, Node** values, int count); |
- void UpdateStateValuesWithCache(Node** state_values, Node** values, |
- int count); |
+ bool StateValuesRequireUpdate(Node** state_values, int offset, int count); |
+ void UpdateStateValues(Node** state_values, int offset, int count); |
int RegisterToValuesIndex(interpreter::Register the_register) const; |
+ |
+ bool IsLivenessBlockConsistent() const; |
Zone* zone() const { return builder_->local_zone(); } |
Graph* graph() const { return builder_->graph(); } |
CommonOperatorBuilder* common() const { return builder_->common(); } |
BytecodeGraphBuilder* builder() const { return builder_; } |
+ LivenessAnalyzerBlock* liveness_block() const { return liveness_block_; } |
const NodeVector* values() const { return &values_; } |
NodeVector* values() { return &values_; } |
int register_base() const { return register_base_; } |
@@ -97,6 +99,7 @@ |
BytecodeGraphBuilder* builder_; |
int register_count_; |
int parameter_count_; |
+ LivenessAnalyzerBlock* liveness_block_; |
Node* context_; |
Node* control_dependency_; |
Node* effect_dependency_; |
@@ -106,10 +109,6 @@ |
Node* accumulator_state_values_; |
int register_base_; |
int accumulator_base_; |
- |
- // A working area for writing maybe-dead values to when updating the state |
- // values for registers. |
- NodeVector state_value_working_area_; |
}; |
@@ -124,14 +123,16 @@ |
: builder_(builder), |
register_count_(register_count), |
parameter_count_(parameter_count), |
+ liveness_block_(builder->is_liveness_analysis_enabled_ |
+ ? builder_->liveness_analyzer()->NewBlock() |
+ : nullptr), |
context_(context), |
control_dependency_(control_dependency), |
effect_dependency_(control_dependency), |
values_(builder->local_zone()), |
parameters_state_values_(nullptr), |
registers_state_values_(nullptr), |
- accumulator_state_values_(nullptr), |
- state_value_working_area_(builder->local_zone()) { |
+ accumulator_state_values_(nullptr) { |
// The layout of values_ is: |
// |
// [receiver] [parameters] [registers] [accumulator] |
@@ -156,15 +157,15 @@ |
// Accumulator |
accumulator_base_ = static_cast<int>(values()->size()); |
values()->push_back(undefined_constant); |
- |
- state_value_working_area_.resize(register_count_); |
} |
BytecodeGraphBuilder::Environment::Environment( |
- const BytecodeGraphBuilder::Environment* other) |
+ const BytecodeGraphBuilder::Environment* other, |
+ LivenessAnalyzerBlock* liveness_block) |
: builder_(other->builder_), |
register_count_(other->register_count_), |
parameter_count_(other->parameter_count_), |
+ liveness_block_(liveness_block), |
context_(other->context_), |
control_dependency_(other->control_dependency_), |
effect_dependency_(other->effect_dependency_), |
@@ -173,9 +174,7 @@ |
registers_state_values_(nullptr), |
accumulator_state_values_(nullptr), |
register_base_(other->register_base_), |
- accumulator_base_(other->accumulator_base_), |
- // Environments can share their working area. |
- state_value_working_area_(other->state_value_working_area_) { |
+ accumulator_base_(other->accumulator_base_) { |
values_ = other->values_; |
} |
@@ -189,7 +188,16 @@ |
} |
} |
+bool BytecodeGraphBuilder::Environment::IsLivenessBlockConsistent() const { |
+ return !builder_->IsLivenessAnalysisEnabled() == |
+ (liveness_block() == nullptr); |
+} |
+ |
Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const { |
+ DCHECK(IsLivenessBlockConsistent()); |
+ if (liveness_block() != nullptr) { |
+ liveness_block()->LookupAccumulator(); |
+ } |
return values()->at(accumulator_base_); |
} |
@@ -204,7 +212,20 @@ |
return builder()->GetNewTarget(); |
} else { |
int values_index = RegisterToValuesIndex(the_register); |
+ if (liveness_block() != nullptr && !the_register.is_parameter()) { |
+ DCHECK(IsLivenessBlockConsistent()); |
+ liveness_block()->Lookup(the_register.index()); |
+ } |
return values()->at(values_index); |
+ } |
+} |
+ |
+void BytecodeGraphBuilder::Environment::MarkAllRegistersLive() { |
+ DCHECK(IsLivenessBlockConsistent()); |
+ if (liveness_block() != nullptr) { |
+ for (int i = 0; i < register_count(); ++i) { |
+ liveness_block()->Lookup(i); |
+ } |
} |
} |
@@ -212,6 +233,10 @@ |
Node* node, FrameStateAttachmentMode mode) { |
if (mode == FrameStateAttachmentMode::kAttachFrameState) { |
builder()->PrepareFrameState(node, OutputFrameStateCombine::PokeAt(0)); |
+ } |
+ DCHECK(IsLivenessBlockConsistent()); |
+ if (liveness_block() != nullptr) { |
+ liveness_block()->BindAccumulator(); |
} |
values()->at(accumulator_base_) = node; |
} |
@@ -225,6 +250,10 @@ |
accumulator_base_ - values_index)); |
} |
values()->at(values_index) = node; |
+ if (liveness_block() != nullptr && !the_register.is_parameter()) { |
+ DCHECK(IsLivenessBlockConsistent()); |
+ liveness_block()->Bind(the_register.index()); |
+ } |
} |
void BytecodeGraphBuilder::Environment::BindRegistersToProjections( |
@@ -252,22 +281,41 @@ |
BytecodeGraphBuilder::Environment* |
BytecodeGraphBuilder::Environment::CopyForLoop() { |
PrepareForLoop(); |
- return new (zone()) Environment(this); |
+ if (liveness_block() != nullptr) { |
+ // Finish the current block before copying. |
+ liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); |
+ } |
+ return new (zone()) Environment(this, liveness_block()); |
} |
BytecodeGraphBuilder::Environment* |
BytecodeGraphBuilder::Environment::CopyForOsrEntry() { |
- return new (zone()) Environment(this); |
+ return new (zone()) |
+ Environment(this, builder_->liveness_analyzer()->NewBlock()); |
} |
BytecodeGraphBuilder::Environment* |
BytecodeGraphBuilder::Environment::CopyForConditional() { |
- return new (zone()) Environment(this); |
+ LivenessAnalyzerBlock* copy_liveness_block = nullptr; |
+ if (liveness_block() != nullptr) { |
+ copy_liveness_block = |
+ builder_->liveness_analyzer()->NewBlock(liveness_block()); |
+ liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); |
+ } |
+ return new (zone()) Environment(this, copy_liveness_block); |
} |
void BytecodeGraphBuilder::Environment::Merge( |
BytecodeGraphBuilder::Environment* other) { |
+ if (builder_->is_liveness_analysis_enabled_) { |
+ if (GetControlDependency()->opcode() != IrOpcode::kLoop) { |
+ liveness_block_ = |
+ builder()->liveness_analyzer()->NewBlock(liveness_block()); |
+ } |
+ liveness_block()->AddPredecessor(other->liveness_block()); |
+ } |
+ |
// Create a merge of the control dependencies of both environments and update |
// the current environment's control dependency accordingly. |
Node* control = builder()->MergeControl(GetControlDependency(), |
@@ -335,7 +383,7 @@ |
BailoutId loop_id(builder_->bytecode_iterator().current_offset()); |
Node* frame_state = |
- Checkpoint(loop_id, OutputFrameStateCombine::Ignore(), false, nullptr); |
+ Checkpoint(loop_id, OutputFrameStateCombine::Ignore(), false); |
Node* checkpoint = |
graph()->NewNode(common()->Checkpoint(), frame_state, entry, entry); |
UpdateEffectDependency(checkpoint); |
@@ -353,13 +401,15 @@ |
} |
bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( |
- Node** state_values, Node** values, int count) { |
+ Node** state_values, int offset, int count) { |
if (*state_values == nullptr) { |
return true; |
} |
DCHECK_EQ((*state_values)->InputCount(), count); |
+ DCHECK_LE(static_cast<size_t>(offset + count), values()->size()); |
+ Node** env_values = (count == 0) ? nullptr : &values()->at(offset); |
for (int i = 0; i < count; i++) { |
- if ((*state_values)->InputAt(i) != values[i]) { |
+ if ((*state_values)->InputAt(i) != env_values[i]) { |
return true; |
} |
} |
@@ -393,51 +443,21 @@ |
} |
void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, |
- Node** values, |
+ int offset, |
int count) { |
- if (StateValuesRequireUpdate(state_values, values, count)) { |
+ if (StateValuesRequireUpdate(state_values, offset, count)) { |
const Operator* op = common()->StateValues(count); |
- (*state_values) = graph()->NewNode(op, count, values); |
- } |
-} |
- |
-void BytecodeGraphBuilder::Environment::UpdateStateValuesWithCache( |
- Node** state_values, Node** values, int count) { |
- *state_values = builder_->state_values_cache_.GetNodeForValues( |
- values, static_cast<size_t>(count)); |
+ (*state_values) = graph()->NewNode(op, count, &values()->at(offset)); |
+ } |
} |
Node* BytecodeGraphBuilder::Environment::Checkpoint( |
BailoutId bailout_id, OutputFrameStateCombine combine, |
- bool owner_has_exception, const BitVector* liveness) { |
- UpdateStateValues(¶meters_state_values_, &values()->at(0), |
- parameter_count()); |
- |
- if (liveness) { |
- Node* optimized_out = builder()->jsgraph()->OptimizedOutConstant(); |
- |
- for (int i = 0; i < register_count(); ++i) { |
- state_value_working_area_[i] = liveness->Contains(i) |
- ? values()->at(register_base() + i) |
- : optimized_out; |
- } |
- |
- Node* accumulator_value = liveness->Contains(register_count()) |
- ? values()->at(accumulator_base()) |
- : optimized_out; |
- |
- UpdateStateValuesWithCache(®isters_state_values_, |
- state_value_working_area_.data(), |
- register_count()); |
- |
- UpdateStateValues(&accumulator_state_values_, &accumulator_value, 1); |
- } else { |
- UpdateStateValuesWithCache(®isters_state_values_, |
- &values()->at(register_base()), |
- register_count()); |
- UpdateStateValues(&accumulator_state_values_, |
- &values()->at(accumulator_base()), 1); |
- } |
+ bool owner_has_exception) { |
+ UpdateStateValues(¶meters_state_values_, 0, parameter_count()); |
+ UpdateStateValues(®isters_state_values_, register_base(), |
+ register_count()); |
+ UpdateStateValues(&accumulator_state_values_, accumulator_base(), 1); |
const Operator* op = common()->FrameState( |
bailout_id, combine, builder()->frame_state_function_info()); |
@@ -445,6 +465,18 @@ |
op, parameters_state_values_, registers_state_values_, |
accumulator_state_values_, Context(), builder()->GetFunctionClosure(), |
builder()->graph()->start()); |
+ |
+ if (liveness_block() != nullptr) { |
+ // If the owning node has an exception, register the checkpoint to the |
+ // predecessor so that the checkpoint is used for both the normal and the |
+ // exceptional paths. Yes, this is a terrible hack and we might want |
+ // to use an explicit frame state for the exceptional path. |
+ if (owner_has_exception) { |
+ liveness_block()->GetPredecessor()->Checkpoint(result); |
+ } else { |
+ liveness_block()->Checkpoint(result); |
+ } |
+ } |
return result; |
} |
@@ -473,6 +505,9 @@ |
exit_controls_(local_zone), |
is_liveness_analysis_enabled_(FLAG_analyze_environment_liveness), |
state_values_cache_(jsgraph), |
+ liveness_analyzer_( |
+ static_cast<size_t>(bytecode_array()->register_count()), true, |
+ local_zone), |
source_positions_(source_positions), |
start_position_(info->shared_info()->start_position(), inlining_id) { |
// Bytecode graph builder assumes deoptimziation is enabled. |
@@ -552,6 +587,8 @@ |
Node** const inputs = &exit_controls_.front(); |
Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); |
graph()->SetEnd(end); |
+ |
+ ClearNonLiveSlotsInFrameStates(); |
return true; |
} |
@@ -565,12 +602,8 @@ |
DCHECK_EQ(IrOpcode::kDead, |
NodeProperties::GetFrameStateInput(node)->opcode()); |
BailoutId bailout_id(bytecode_iterator().current_offset()); |
- |
- const BitVector* liveness_before = bytecode_analysis()->GetInLivenessFor( |
- bytecode_iterator().current_offset()); |
- |
Node* frame_state_before = environment()->Checkpoint( |
- bailout_id, OutputFrameStateCombine::Ignore(), false, liveness_before); |
+ bailout_id, OutputFrameStateCombine::Ignore(), false); |
NodeProperties::ReplaceFrameStateInput(node, frame_state_before); |
} |
} |
@@ -585,19 +618,28 @@ |
NodeProperties::GetFrameStateInput(node)->opcode()); |
BailoutId bailout_id(bytecode_iterator().current_offset()); |
bool has_exception = NodeProperties::IsExceptionalCall(node); |
- |
- const BitVector* liveness_after = bytecode_analysis()->GetOutLivenessFor( |
- bytecode_iterator().current_offset()); |
- |
- Node* frame_state_after = environment()->Checkpoint( |
- bailout_id, combine, has_exception, liveness_after); |
+ Node* frame_state_after = |
+ environment()->Checkpoint(bailout_id, combine, has_exception); |
NodeProperties::ReplaceFrameStateInput(node, frame_state_after); |
} |
} |
+void BytecodeGraphBuilder::ClearNonLiveSlotsInFrameStates() { |
+ if (!IsLivenessAnalysisEnabled()) { |
+ return; |
+ } |
+ NonLiveFrameStateSlotReplacer replacer( |
+ &state_values_cache_, jsgraph()->OptimizedOutConstant(), |
+ liveness_analyzer()->local_count(), true, local_zone()); |
+ liveness_analyzer()->Run(&replacer); |
+ if (FLAG_trace_environment_liveness) { |
+ OFStream os(stdout); |
+ liveness_analyzer()->Print(os); |
+ } |
+} |
+ |
void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) { |
- BytecodeAnalysis bytecode_analysis(bytecode_array(), local_zone(), |
- FLAG_analyze_environment_liveness); |
+ BytecodeAnalysis bytecode_analysis(bytecode_array(), local_zone()); |
bytecode_analysis.Analyze(); |
set_bytecode_analysis(&bytecode_analysis); |
@@ -606,14 +648,7 @@ |
SourcePositionTableIterator source_position_iterator( |
bytecode_array()->source_position_table()); |
- if (FLAG_trace_environment_liveness) { |
- OFStream of(stdout); |
- |
- bytecode_analysis.PrintLivenessTo(of); |
- } |
- |
BuildOSRNormalEntryPoint(); |
- |
for (; !iterator.done(); iterator.Advance()) { |
int current_offset = iterator.current_offset(); |
UpdateCurrentSourcePosition(&source_position_iterator, current_offset); |
@@ -1734,6 +1769,7 @@ |
Node* call = |
NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement)); |
environment()->BindAccumulator(call, Environment::kAttachFrameState); |
+ environment()->MarkAllRegistersLive(); |
} |
// We cannot create a graph from the debugger copy of the bytecode array. |