Commit d2ca18d8 authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Fix variable liveness control structure creation.

R=bmeurer@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#28536}
parent f2ffa6ad
...@@ -599,7 +599,10 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) { ...@@ -599,7 +599,10 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) {
void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() { void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
if (!FLAG_analyze_environment_liveness) return; if (!FLAG_analyze_environment_liveness ||
!info()->is_deoptimization_enabled()) {
return;
}
NonLiveFrameStateSlotReplacer replacer( NonLiveFrameStateSlotReplacer replacer(
&state_values_cache_, jsgraph()->UndefinedConstant(), &state_values_cache_, jsgraph()->UndefinedConstant(),
...@@ -660,7 +663,9 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, ...@@ -660,7 +663,9 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
: builder_(builder), : builder_(builder),
parameters_count_(scope->num_parameters() + 1), parameters_count_(scope->num_parameters() + 1),
locals_count_(scope->num_stack_slots()), locals_count_(scope->num_stack_slots()),
liveness_block_(builder_->liveness_analyzer()->NewBlock()), liveness_block_(IsLivenessAnalysisEnabled()
? builder_->liveness_analyzer()->NewBlock()
: nullptr),
values_(builder_->local_zone()), values_(builder_->local_zone()),
contexts_(builder_->local_zone()), contexts_(builder_->local_zone()),
control_dependency_(control_dependency), control_dependency_(control_dependency),
...@@ -696,10 +701,12 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, ...@@ -696,10 +701,12 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
} }
AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy) AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy,
LivenessAnalyzerBlock* liveness_block)
: builder_(copy->builder_), : builder_(copy->builder_),
parameters_count_(copy->parameters_count_), parameters_count_(copy->parameters_count_),
locals_count_(copy->locals_count_), locals_count_(copy->locals_count_),
liveness_block_(liveness_block),
values_(copy->zone()), values_(copy->zone()),
contexts_(copy->zone()), contexts_(copy->zone()),
control_dependency_(copy->control_dependency_), control_dependency_(copy->control_dependency_),
...@@ -713,14 +720,6 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy) ...@@ -713,14 +720,6 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy)
contexts_.reserve(copy->contexts_.size()); contexts_.reserve(copy->contexts_.size());
contexts_.insert(contexts_.begin(), copy->contexts_.begin(), contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
copy->contexts_.end()); copy->contexts_.end());
if (FLAG_analyze_environment_liveness) {
// Split the liveness blocks.
copy->liveness_block_ =
builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
liveness_block_ =
builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
}
} }
...@@ -733,7 +732,9 @@ void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) { ...@@ -733,7 +732,9 @@ void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) {
} else { } else {
DCHECK(variable->IsStackLocal()); DCHECK(variable->IsStackLocal());
values()->at(variable->index() + parameters_count_) = node; values()->at(variable->index() + parameters_count_) = node;
if (FLAG_analyze_environment_liveness) {
DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
liveness_block()->Bind(variable->index()); liveness_block()->Bind(variable->index());
} }
} }
...@@ -748,7 +749,8 @@ Node* AstGraphBuilder::Environment::Lookup(Variable* variable) { ...@@ -748,7 +749,8 @@ Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
return values()->at(variable->index() + 1); return values()->at(variable->index() + 1);
} else { } else {
DCHECK(variable->IsStackLocal()); DCHECK(variable->IsStackLocal());
if (FLAG_analyze_environment_liveness) { DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
liveness_block()->Lookup(variable->index()); liveness_block()->Lookup(variable->index());
} }
return values()->at(variable->index() + parameters_count_); return values()->at(variable->index() + parameters_count_);
...@@ -757,7 +759,8 @@ Node* AstGraphBuilder::Environment::Lookup(Variable* variable) { ...@@ -757,7 +759,8 @@ Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
void AstGraphBuilder::Environment::MarkAllLocalsLive() { void AstGraphBuilder::Environment::MarkAllLocalsLive() {
if (FLAG_analyze_environment_liveness) { DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
for (int i = 0; i < locals_count_; i++) { for (int i = 0; i < locals_count_; i++) {
liveness_block()->Lookup(i); liveness_block()->Lookup(i);
} }
...@@ -765,16 +768,44 @@ void AstGraphBuilder::Environment::MarkAllLocalsLive() { ...@@ -765,16 +768,44 @@ void AstGraphBuilder::Environment::MarkAllLocalsLive() {
} }
AstGraphBuilder::Environment*
AstGraphBuilder::Environment::CopyForConditional() {
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);
}
AstGraphBuilder::Environment*
AstGraphBuilder::Environment::CopyAsUnreachable() {
Environment* env = new (zone()) Environment(this, nullptr);
env->MarkAsUnreachable();
return env;
}
AstGraphBuilder::Environment* AstGraphBuilder::Environment*
AstGraphBuilder::Environment::CopyAndShareLiveness() { AstGraphBuilder::Environment::CopyAndShareLiveness() {
Environment* env = new (zone()) Environment(this); if (liveness_block() != nullptr) {
if (FLAG_analyze_environment_liveness) { // Finish the current liveness block before copying.
env->liveness_block_ = liveness_block(); liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
} }
Environment* env = new (zone()) Environment(this, liveness_block());
return env; return env;
} }
AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForLoop(
BitVector* assigned, bool is_osr) {
PrepareForLoop(assigned, is_osr);
return CopyAndShareLiveness();
}
void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
int offset, int count) { int offset, int count) {
bool should_update = false; bool should_update = false;
...@@ -822,13 +853,27 @@ Node* AstGraphBuilder::Environment::Checkpoint( ...@@ -822,13 +853,27 @@ Node* AstGraphBuilder::Environment::Checkpoint(
stack_node_, builder()->current_context(), stack_node_, builder()->current_context(),
builder()->GetFunctionClosure(), builder()->GetFunctionClosure(),
builder()->jsgraph()->UndefinedConstant()); builder()->jsgraph()->UndefinedConstant());
if (FLAG_analyze_environment_liveness) {
DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
liveness_block()->Checkpoint(result); liveness_block()->Checkpoint(result);
} }
return result; return result;
} }
bool AstGraphBuilder::Environment::IsLivenessAnalysisEnabled() {
return FLAG_analyze_environment_liveness &&
builder()->info()->is_deoptimization_enabled();
}
bool AstGraphBuilder::Environment::IsLivenessBlockConsistent() {
return (!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()) ==
(liveness_block() == nullptr);
}
AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
Expression::Context kind) Expression::Context kind)
: kind_(kind), owner_(own), outer_(own->ast_context()) { : kind_(kind), owner_(own), outer_(own->ast_context()) {
...@@ -3505,9 +3550,13 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count, ...@@ -3505,9 +3550,13 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
} }
// Add implicit exception continuation for throwing nodes. // Add implicit exception continuation for throwing nodes.
if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) {
// Copy the environment for the success continuation.
Environment* success_env = environment()->CopyForConditional();
Node* on_exception = graph()->NewNode(common()->IfException(), result); Node* on_exception = graph()->NewNode(common()->IfException(), result);
environment_->UpdateControlDependency(on_exception); environment_->UpdateControlDependency(on_exception);
execution_control()->ThrowValue(on_exception); execution_control()->ThrowValue(on_exception);
set_environment(success_env);
} }
// Add implicit success continuation for throwing nodes. // Add implicit success continuation for throwing nodes.
if (!result->op()->HasProperty(Operator::kNoThrow)) { if (!result->op()->HasProperty(Operator::kNoThrow)) {
...@@ -3543,21 +3592,23 @@ void AstGraphBuilder::Environment::Merge(Environment* other) { ...@@ -3543,21 +3592,23 @@ void AstGraphBuilder::Environment::Merge(Environment* other) {
if (this->IsMarkedAsUnreachable()) { if (this->IsMarkedAsUnreachable()) {
Node* other_control = other->control_dependency_; Node* other_control = other->control_dependency_;
Node* inputs[] = {other_control}; Node* inputs[] = {other_control};
liveness_block_ = other->liveness_block_;
control_dependency_ = control_dependency_ =
graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
effect_dependency_ = other->effect_dependency_; effect_dependency_ = other->effect_dependency_;
values_ = other->values_; values_ = other->values_;
contexts_ = other->contexts_; contexts_ = other->contexts_;
if (IsLivenessAnalysisEnabled()) {
liveness_block_ =
builder_->liveness_analyzer()->NewBlock(other->liveness_block());
}
return; return;
} }
// Record the merge for the local variable liveness calculation. // Record the merge for the local variable liveness calculation.
// Unfortunately, we have to mirror the logic in the MergeControl method: // For loops, we are connecting a back edge into the existing block;
// connect before merge or loop, or create a new merge otherwise. // for merges, we create a new merged block.
if (FLAG_analyze_environment_liveness) { if (IsLivenessAnalysisEnabled()) {
if (GetControlDependency()->opcode() != IrOpcode::kLoop && if (GetControlDependency()->opcode() != IrOpcode::kLoop) {
GetControlDependency()->opcode() != IrOpcode::kMerge) {
liveness_block_ = liveness_block_ =
builder_->liveness_analyzer()->NewBlock(liveness_block()); builder_->liveness_analyzer()->NewBlock(liveness_block());
} }
......
...@@ -459,6 +459,7 @@ class AstGraphBuilder::Environment : public ZoneObject { ...@@ -459,6 +459,7 @@ class AstGraphBuilder::Environment : public ZoneObject {
// Mark this environment as being unreachable. // Mark this environment as being unreachable.
void MarkAsUnreachable() { void MarkAsUnreachable() {
UpdateControlDependency(builder()->jsgraph()->DeadControl()); UpdateControlDependency(builder()->jsgraph()->DeadControl());
liveness_block_ = nullptr;
} }
bool IsMarkedAsUnreachable() { bool IsMarkedAsUnreachable() {
return GetControlDependency()->opcode() == IrOpcode::kDead; return GetControlDependency()->opcode() == IrOpcode::kDead;
...@@ -468,20 +469,13 @@ class AstGraphBuilder::Environment : public ZoneObject { ...@@ -468,20 +469,13 @@ class AstGraphBuilder::Environment : public ZoneObject {
void Merge(Environment* other); void Merge(Environment* other);
// Copies this environment at a control-flow split point. // Copies this environment at a control-flow split point.
Environment* CopyForConditional() { return Copy(); } Environment* CopyForConditional();
// Copies this environment to a potentially unreachable control-flow point. // Copies this environment to a potentially unreachable control-flow point.
Environment* CopyAsUnreachable() { Environment* CopyAsUnreachable();
Environment* env = Copy();
env->MarkAsUnreachable();
return env;
}
// Copies this environment at a loop header control-flow point. // Copies this environment at a loop header control-flow point.
Environment* CopyForLoop(BitVector* assigned, bool is_osr = false) { Environment* CopyForLoop(BitVector* assigned, bool is_osr = false);
PrepareForLoop(assigned, is_osr);
return CopyAndShareLiveness();
}
private: private:
AstGraphBuilder* builder_; AstGraphBuilder* builder_;
...@@ -496,8 +490,8 @@ class AstGraphBuilder::Environment : public ZoneObject { ...@@ -496,8 +490,8 @@ class AstGraphBuilder::Environment : public ZoneObject {
Node* locals_node_; Node* locals_node_;
Node* stack_node_; Node* stack_node_;
explicit Environment(Environment* copy); explicit Environment(Environment* copy,
Environment* Copy() { return new (zone()) Environment(this); } LivenessAnalyzerBlock* liveness_block);
Environment* CopyAndShareLiveness(); Environment* CopyAndShareLiveness();
void UpdateStateValues(Node** state_values, int offset, int count); void UpdateStateValues(Node** state_values, int offset, int count);
void UpdateStateValuesWithCache(Node** state_values, int offset, int count); void UpdateStateValuesWithCache(Node** state_values, int offset, int count);
...@@ -508,6 +502,8 @@ class AstGraphBuilder::Environment : public ZoneObject { ...@@ -508,6 +502,8 @@ class AstGraphBuilder::Environment : public ZoneObject {
NodeVector* values() { return &values_; } NodeVector* values() { return &values_; }
NodeVector* contexts() { return &contexts_; } NodeVector* contexts() { return &contexts_; }
LivenessAnalyzerBlock* liveness_block() { return liveness_block_; } LivenessAnalyzerBlock* liveness_block() { return liveness_block_; }
bool IsLivenessAnalysisEnabled();
bool IsLivenessBlockConsistent();
// Prepare environment to be used as loop header. // Prepare environment to be used as loop header.
void PrepareForLoop(BitVector* assigned, bool is_osr = false); void PrepareForLoop(BitVector* assigned, bool is_osr = false);
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function foo(x) {
%DeoptimizeFunction(run);
return x;
}
function run() {
var line = new Array(2);
for (var n = 3; n > 0; n = n - 1) {
if (n < foo(line.length)) line = new Array(n);
line[0] = n;
}
}
assertEquals(void 0, run());
%OptimizeFunctionOnNextCall(run);
assertEquals(void 0, run());
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