Commit 99248f4d authored by jgruber's avatar jgruber Committed by Commit Bot

[interpreter] Add ConditionalControlFlowBuilder

This refactors logic for handling IfStatement and Conditional nodes (including
block-coverage related slot and counter creation) into a new control-flow
builder.

Bug: v8:6000
Change-Id: Ib5b1724bdf8571fb55d310be79cc60dcf5473b81
Reviewed-on: https://chromium-review.googlesource.com/579509Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46818}
parent 5d0a4327
......@@ -1201,48 +1201,36 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
}
void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
ConditionalControlFlowBuilder conditional_builder(
builder(), block_coverage_builder_, stmt);
builder()->SetStatementPosition(stmt);
int then_slot =
AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kThen);
int else_slot =
AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kElse);
if (stmt->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true.
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
conditional_builder.Then();
Visit(stmt->then_statement());
} else if (stmt->condition()->ToBooleanIsFalse()) {
// Generate else block unconditionally if it exists.
if (stmt->HasElseStatement()) {
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
conditional_builder.Else();
Visit(stmt->else_statement());
}
} else {
// TODO(oth): If then statement is BreakStatement or
// ContinueStatement we can reduce number of generated
// jump/jump_ifs here. See BasicLoops test.
BytecodeLabel end_label;
BytecodeLabels then_labels(zone()), else_labels(zone());
VisitForTest(stmt->condition(), &then_labels, &else_labels,
TestFallthrough::kThen);
VisitForTest(stmt->condition(), conditional_builder.then_labels(),
conditional_builder.else_labels(), TestFallthrough::kThen);
then_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
conditional_builder.Then();
Visit(stmt->then_statement());
if (stmt->HasElseStatement()) {
builder()->Jump(&end_label);
else_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
conditional_builder.JumpToEnd();
conditional_builder.Else();
Visit(stmt->else_statement());
} else {
else_labels.Bind(builder());
}
builder()->Bind(&end_label);
}
BuildIncrementBlockCoverageCounterIfEnabled(stmt,
SourceRangeKind::kContinuation);
}
void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
......@@ -1819,35 +1807,27 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
}
void BytecodeGenerator::VisitConditional(Conditional* expr) {
int then_slot =
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kThen);
int else_slot =
AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kElse);
ConditionalControlFlowBuilder conditional_builder(
builder(), block_coverage_builder_, expr);
if (expr->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true.
conditional_builder.Then();
VisitForAccumulatorValue(expr->then_expression());
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
} else if (expr->condition()->ToBooleanIsFalse()) {
// Generate else block unconditionally if it exists.
conditional_builder.Else();
VisitForAccumulatorValue(expr->else_expression());
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
} else {
BytecodeLabel end_label;
BytecodeLabels then_labels(zone()), else_labels(zone());
VisitForTest(expr->condition(), &then_labels, &else_labels,
TestFallthrough::kThen);
VisitForTest(expr->condition(), conditional_builder.then_labels(),
conditional_builder.else_labels(), TestFallthrough::kThen);
then_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
conditional_builder.Then();
VisitForAccumulatorValue(expr->then_expression());
builder()->Jump(&end_label);
conditional_builder.JumpToEnd();
else_labels.Bind(builder());
BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
conditional_builder.Else();
VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label);
}
}
......
......@@ -160,6 +160,41 @@ void TryFinallyBuilder::EndFinally() {
// Nothing to be done here.
}
ConditionalControlFlowBuilder::~ConditionalControlFlowBuilder() {
if (!else_labels_.is_bound()) else_labels_.Bind(builder());
end_labels_.Bind(builder());
DCHECK(end_labels_.empty() || end_labels_.is_bound());
DCHECK(then_labels_.empty() || then_labels_.is_bound());
DCHECK(else_labels_.empty() || else_labels_.is_bound());
// IfStatement requires a continuation counter, Conditional does not (as it
// can only contain expressions).
if (block_coverage_builder_ != nullptr && node_->IsIfStatement()) {
block_coverage_builder_->IncrementBlockCounter(
node_, SourceRangeKind::kContinuation);
}
}
void ConditionalControlFlowBuilder::JumpToEnd() {
DCHECK(end_labels_.empty()); // May only be called once.
builder()->Jump(end_labels_.New());
}
void ConditionalControlFlowBuilder::Then() {
then_labels()->Bind(builder());
if (block_coverage_builder_ != nullptr) {
block_coverage_builder_->IncrementBlockCounter(block_coverage_then_slot_);
}
}
void ConditionalControlFlowBuilder::Else() {
else_labels()->Bind(builder());
if (block_coverage_builder_ != nullptr) {
block_coverage_builder_->IncrementBlockCounter(block_coverage_else_slot_);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -231,6 +231,49 @@ class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder {
BytecodeLabels finalization_sites_;
};
class V8_EXPORT_PRIVATE ConditionalControlFlowBuilder final
: public ControlFlowBuilder {
public:
ConditionalControlFlowBuilder(BytecodeArrayBuilder* builder,
BlockCoverageBuilder* block_coverage_builder,
AstNode* node)
: ControlFlowBuilder(builder),
end_labels_(builder->zone()),
then_labels_(builder->zone()),
else_labels_(builder->zone()),
node_(node),
block_coverage_builder_(block_coverage_builder) {
DCHECK(node->IsIfStatement() || node->IsConditional());
if (block_coverage_builder != nullptr) {
block_coverage_then_slot_ =
block_coverage_builder->AllocateBlockCoverageSlot(
node, SourceRangeKind::kThen);
block_coverage_else_slot_ =
block_coverage_builder->AllocateBlockCoverageSlot(
node, SourceRangeKind::kElse);
}
}
~ConditionalControlFlowBuilder();
BytecodeLabels* then_labels() { return &then_labels_; }
BytecodeLabels* else_labels() { return &else_labels_; }
void Then();
void Else();
void JumpToEnd();
private:
BytecodeLabels end_labels_;
BytecodeLabels then_labels_;
BytecodeLabels else_labels_;
AstNode* node_;
int block_coverage_then_slot_;
int block_coverage_else_slot_;
BlockCoverageBuilder* block_coverage_builder_;
};
} // namespace interpreter
} // namespace internal
} // namespace v8
......
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