Commit 9c068209 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[turbofan] Improve checkpoint elision during graph building.

This improves the filter deciding whether a checkpoint needs to be
created. We now keep track of whether a node having an observable
side-effect has been created, allowing to elide checkpoint that are
provably effect-dominated by another checkpoint already.

By now the initial graphs contain an increasing amount of nodes marked
with {Operator::kNoWrite}, making this optimization worthwhile.

R=jarin@chromium.org

Change-Id: Ie7ffb67e1ab081ef7aa3017675afbe5f9e7601ab
Reviewed-on: https://chromium-review.googlesource.com/443466Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43256}
parent 7eb022c8
...@@ -487,6 +487,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder( ...@@ -487,6 +487,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
current_exception_handler_(0), current_exception_handler_(0),
input_buffer_size_(0), input_buffer_size_(0),
input_buffer_(nullptr), input_buffer_(nullptr),
needs_eager_checkpoint_(true),
exit_controls_(local_zone), exit_controls_(local_zone),
state_values_cache_(jsgraph), state_values_cache_(jsgraph),
source_positions_(source_positions), source_positions_(source_positions),
...@@ -572,9 +573,10 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) { ...@@ -572,9 +573,10 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
} }
void BytecodeGraphBuilder::PrepareEagerCheckpoint() { void BytecodeGraphBuilder::PrepareEagerCheckpoint() {
if (environment()->GetEffectDependency()->opcode() != IrOpcode::kCheckpoint) { if (needs_eager_checkpoint()) {
// Create an explicit checkpoint node for before the operation. This only // Create an explicit checkpoint node for before the operation. This only
// needs to happen if we aren't effect-dominated by a {Checkpoint} already. // needs to happen if we aren't effect-dominated by a {Checkpoint} already.
mark_as_needing_eager_checkpoint(false);
Node* node = NewNode(common()->Checkpoint()); Node* node = NewNode(common()->Checkpoint());
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(IrOpcode::kDead, DCHECK_EQ(IrOpcode::kDead,
...@@ -588,7 +590,21 @@ void BytecodeGraphBuilder::PrepareEagerCheckpoint() { ...@@ -588,7 +590,21 @@ void BytecodeGraphBuilder::PrepareEagerCheckpoint() {
Node* frame_state_before = environment()->Checkpoint( Node* frame_state_before = environment()->Checkpoint(
bailout_id, OutputFrameStateCombine::Ignore(), false, liveness_before); bailout_id, OutputFrameStateCombine::Ignore(), false, liveness_before);
NodeProperties::ReplaceFrameStateInput(node, frame_state_before); NodeProperties::ReplaceFrameStateInput(node, frame_state_before);
#ifdef DEBUG
} else {
// In case we skipped checkpoint creation above, we must be able to find an
// existing checkpoint that effect-dominates the nodes about to be created.
// Starting a search from the current effect-dependency has to succeed.
Node* effect = environment()->GetEffectDependency();
while (effect->opcode() != IrOpcode::kCheckpoint) {
DCHECK(effect->op()->HasProperty(Operator::kNoWrite));
DCHECK_EQ(1, effect->op()->EffectInputCount());
effect = NodeProperties::GetEffectInput(effect);
}
} }
#else
}
#endif // DEBUG
} }
void BytecodeGraphBuilder::PrepareFrameState(Node* node, void BytecodeGraphBuilder::PrepareFrameState(Node* node,
...@@ -940,6 +956,7 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) { ...@@ -940,6 +956,7 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) {
fast_environment->Merge(environment()); fast_environment->Merge(environment());
set_environment(fast_environment); set_environment(fast_environment);
mark_as_needing_eager_checkpoint(true);
} }
} }
...@@ -989,6 +1006,7 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) { ...@@ -989,6 +1006,7 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
fast_environment->Merge(environment()); fast_environment->Merge(environment());
set_environment(fast_environment); set_environment(fast_environment);
mark_as_needing_eager_checkpoint(true);
} }
} }
...@@ -1462,17 +1480,11 @@ void BytecodeGraphBuilder::VisitConstruct() { ...@@ -1462,17 +1480,11 @@ void BytecodeGraphBuilder::VisitConstruct() {
environment()->BindAccumulator(value, Environment::kAttachFrameState); environment()->BindAccumulator(value, Environment::kAttachFrameState);
} }
void BytecodeGraphBuilder::BuildThrow() { void BytecodeGraphBuilder::VisitThrow() {
PrepareEagerCheckpoint(); BuildLoopExitsForFunctionExit();
Node* value = environment()->LookupAccumulator(); Node* value = environment()->LookupAccumulator();
Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value); Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value);
environment()->BindAccumulator(call, Environment::kAttachFrameState); environment()->BindAccumulator(call, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitThrow() {
BuildLoopExitsForFunctionExit();
BuildThrow();
Node* call = environment()->LookupAccumulator();
Node* control = NewNode(common()->Throw(), call); Node* control = NewNode(common()->Throw(), call);
MergeControlToLeaveFunction(control); MergeControlToLeaveFunction(control);
} }
...@@ -2013,6 +2025,7 @@ void BytecodeGraphBuilder::VisitNop() {} ...@@ -2013,6 +2025,7 @@ void BytecodeGraphBuilder::VisitNop() {}
void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) { void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
auto it = merge_environments_.find(current_offset); auto it = merge_environments_.find(current_offset);
if (it != merge_environments_.end()) { if (it != merge_environments_.end()) {
mark_as_needing_eager_checkpoint(true);
if (environment() != nullptr) { if (environment() != nullptr) {
it->second->Merge(environment()); it->second->Merge(environment());
} }
...@@ -2022,6 +2035,7 @@ void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) { ...@@ -2022,6 +2035,7 @@ void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
if (bytecode_analysis()->IsLoopHeader(current_offset)) { if (bytecode_analysis()->IsLoopHeader(current_offset)) {
mark_as_needing_eager_checkpoint(true);
const LoopInfo& loop_info = const LoopInfo& loop_info =
bytecode_analysis()->GetLoopInfoFor(current_offset); bytecode_analysis()->GetLoopInfoFor(current_offset);
...@@ -2290,6 +2304,10 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, ...@@ -2290,6 +2304,10 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
Node* on_success = graph()->NewNode(if_success, result); Node* on_success = graph()->NewNode(if_success, result);
environment()->UpdateControlDependency(on_success); environment()->UpdateControlDependency(on_success);
} }
// Ensure checkpoints are created after operations with side-effects.
if (has_effect && !result->op()->HasProperty(Operator::kNoWrite)) {
mark_as_needing_eager_checkpoint(true);
}
} }
return result; return result;
......
...@@ -145,7 +145,6 @@ class BytecodeGraphBuilder { ...@@ -145,7 +145,6 @@ class BytecodeGraphBuilder {
void BuildStaLookupSlot(LanguageMode language_mode); void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCall(TailCallMode tail_call_mode, void BuildCall(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_hint); ConvertReceiverMode receiver_hint);
void BuildThrow();
void BuildBinaryOp(const Operator* op); void BuildBinaryOp(const Operator* op);
void BuildBinaryOpWithImmediate(const Operator* op); void BuildBinaryOpWithImmediate(const Operator* op);
void BuildCompareOp(const Operator* op); void BuildCompareOp(const Operator* op);
...@@ -269,6 +268,11 @@ class BytecodeGraphBuilder { ...@@ -269,6 +268,11 @@ class BytecodeGraphBuilder {
bytecode_analysis_ = bytecode_analysis; bytecode_analysis_ = bytecode_analysis;
} }
bool needs_eager_checkpoint() const { return needs_eager_checkpoint_; }
void mark_as_needing_eager_checkpoint(bool value) {
needs_eager_checkpoint_ = value;
}
#define DECLARE_VISIT_BYTECODE(name, ...) void Visit##name(); #define DECLARE_VISIT_BYTECODE(name, ...) void Visit##name();
BYTECODE_LIST(DECLARE_VISIT_BYTECODE) BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
#undef DECLARE_VISIT_BYTECODE #undef DECLARE_VISIT_BYTECODE
...@@ -299,6 +303,11 @@ class BytecodeGraphBuilder { ...@@ -299,6 +303,11 @@ class BytecodeGraphBuilder {
int input_buffer_size_; int input_buffer_size_;
Node** input_buffer_; Node** input_buffer_;
// Optimization to only create checkpoints when the current position in the
// control-flow is not effect-dominated by another checkpoint already. All
// operations that do not have observable side-effects can be re-evaluated.
bool needs_eager_checkpoint_;
// Nodes representing values in the activation record. // Nodes representing values in the activation record.
SetOncePointer<Node> function_context_; SetOncePointer<Node> function_context_;
SetOncePointer<Node> function_closure_; SetOncePointer<Node> function_closure_;
......
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