[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/579509 Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#46818}
This commit is contained in:
parent
5d0a4327c7
commit
99248f4d86
@ -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(), conditional_builder.then_labels(),
|
||||
conditional_builder.else_labels(), TestFallthrough::kThen);
|
||||
|
||||
VisitForTest(expr->condition(), &then_labels, &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
|
||||
|
Loading…
Reference in New Issue
Block a user