[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}
This commit is contained in:
jarin 2015-05-21 02:57:27 -07:00 committed by Commit bot
parent f2ffa6ade5
commit d2ca18d849
3 changed files with 106 additions and 37 deletions

View File

@ -599,7 +599,10 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) {
void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
if (!FLAG_analyze_environment_liveness) return;
if (!FLAG_analyze_environment_liveness ||
!info()->is_deoptimization_enabled()) {
return;
}
NonLiveFrameStateSlotReplacer replacer(
&state_values_cache_, jsgraph()->UndefinedConstant(),
@ -660,7 +663,9 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
: builder_(builder),
parameters_count_(scope->num_parameters() + 1),
locals_count_(scope->num_stack_slots()),
liveness_block_(builder_->liveness_analyzer()->NewBlock()),
liveness_block_(IsLivenessAnalysisEnabled()
? builder_->liveness_analyzer()->NewBlock()
: nullptr),
values_(builder_->local_zone()),
contexts_(builder_->local_zone()),
control_dependency_(control_dependency),
@ -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_),
parameters_count_(copy->parameters_count_),
locals_count_(copy->locals_count_),
liveness_block_(liveness_block),
values_(copy->zone()),
contexts_(copy->zone()),
control_dependency_(copy->control_dependency_),
@ -713,14 +720,6 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy)
contexts_.reserve(copy->contexts_.size());
contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
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) {
} else {
DCHECK(variable->IsStackLocal());
values()->at(variable->index() + parameters_count_) = node;
if (FLAG_analyze_environment_liveness) {
DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
liveness_block()->Bind(variable->index());
}
}
@ -748,7 +749,8 @@ Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
return values()->at(variable->index() + 1);
} else {
DCHECK(variable->IsStackLocal());
if (FLAG_analyze_environment_liveness) {
DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
liveness_block()->Lookup(variable->index());
}
return values()->at(variable->index() + parameters_count_);
@ -757,7 +759,8 @@ Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
void AstGraphBuilder::Environment::MarkAllLocalsLive() {
if (FLAG_analyze_environment_liveness) {
DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
for (int i = 0; i < locals_count_; i++) {
liveness_block()->Lookup(i);
}
@ -766,15 +769,43 @@ void AstGraphBuilder::Environment::MarkAllLocalsLive() {
AstGraphBuilder::Environment*
AstGraphBuilder::Environment::CopyAndShareLiveness() {
Environment* env = new (zone()) Environment(this);
if (FLAG_analyze_environment_liveness) {
env->liveness_block_ = liveness_block();
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::CopyAndShareLiveness() {
if (liveness_block() != nullptr) {
// Finish the current liveness block before copying.
liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
}
Environment* env = new (zone()) Environment(this, liveness_block());
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,
int offset, int count) {
bool should_update = false;
@ -822,13 +853,27 @@ Node* AstGraphBuilder::Environment::Checkpoint(
stack_node_, builder()->current_context(),
builder()->GetFunctionClosure(),
builder()->jsgraph()->UndefinedConstant());
if (FLAG_analyze_environment_liveness) {
DCHECK(IsLivenessBlockConsistent());
if (liveness_block() != nullptr) {
liveness_block()->Checkpoint(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,
Expression::Context kind)
: kind_(kind), owner_(own), outer_(own->ast_context()) {
@ -3505,9 +3550,13 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
}
// Add implicit exception continuation for throwing nodes.
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);
environment_->UpdateControlDependency(on_exception);
execution_control()->ThrowValue(on_exception);
set_environment(success_env);
}
// Add implicit success continuation for throwing nodes.
if (!result->op()->HasProperty(Operator::kNoThrow)) {
@ -3543,21 +3592,23 @@ void AstGraphBuilder::Environment::Merge(Environment* other) {
if (this->IsMarkedAsUnreachable()) {
Node* other_control = other->control_dependency_;
Node* inputs[] = {other_control};
liveness_block_ = other->liveness_block_;
control_dependency_ =
graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
effect_dependency_ = other->effect_dependency_;
values_ = other->values_;
contexts_ = other->contexts_;
if (IsLivenessAnalysisEnabled()) {
liveness_block_ =
builder_->liveness_analyzer()->NewBlock(other->liveness_block());
}
return;
}
// Record the merge for the local variable liveness calculation.
// Unfortunately, we have to mirror the logic in the MergeControl method:
// connect before merge or loop, or create a new merge otherwise.
if (FLAG_analyze_environment_liveness) {
if (GetControlDependency()->opcode() != IrOpcode::kLoop &&
GetControlDependency()->opcode() != IrOpcode::kMerge) {
// For loops, we are connecting a back edge into the existing block;
// for merges, we create a new merged block.
if (IsLivenessAnalysisEnabled()) {
if (GetControlDependency()->opcode() != IrOpcode::kLoop) {
liveness_block_ =
builder_->liveness_analyzer()->NewBlock(liveness_block());
}

View File

@ -459,6 +459,7 @@ class AstGraphBuilder::Environment : public ZoneObject {
// Mark this environment as being unreachable.
void MarkAsUnreachable() {
UpdateControlDependency(builder()->jsgraph()->DeadControl());
liveness_block_ = nullptr;
}
bool IsMarkedAsUnreachable() {
return GetControlDependency()->opcode() == IrOpcode::kDead;
@ -468,20 +469,13 @@ class AstGraphBuilder::Environment : public ZoneObject {
void Merge(Environment* other);
// 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.
Environment* CopyAsUnreachable() {
Environment* env = Copy();
env->MarkAsUnreachable();
return env;
}
Environment* CopyAsUnreachable();
// Copies this environment at a loop header control-flow point.
Environment* CopyForLoop(BitVector* assigned, bool is_osr = false) {
PrepareForLoop(assigned, is_osr);
return CopyAndShareLiveness();
}
Environment* CopyForLoop(BitVector* assigned, bool is_osr = false);
private:
AstGraphBuilder* builder_;
@ -496,8 +490,8 @@ class AstGraphBuilder::Environment : public ZoneObject {
Node* locals_node_;
Node* stack_node_;
explicit Environment(Environment* copy);
Environment* Copy() { return new (zone()) Environment(this); }
explicit Environment(Environment* copy,
LivenessAnalyzerBlock* liveness_block);
Environment* CopyAndShareLiveness();
void UpdateStateValues(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 {
NodeVector* values() { return &values_; }
NodeVector* contexts() { return &contexts_; }
LivenessAnalyzerBlock* liveness_block() { return liveness_block_; }
bool IsLivenessAnalysisEnabled();
bool IsLivenessBlockConsistent();
// Prepare environment to be used as loop header.
void PrepareForLoop(BitVector* assigned, bool is_osr = false);

View File

@ -0,0 +1,22 @@
// 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());