| Index: src/interpreter/bytecode-generator.cc
|
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
|
| index b754897e759335c90ea8c4a94555f3d22d3e6a9f..59173891f0a14f63bfdc671ad8b958e01a06e707 100644
|
| --- a/src/interpreter/bytecode-generator.cc
|
| +++ b/src/interpreter/bytecode-generator.cc
|
| @@ -737,6 +737,36 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
|
| bool has_constant_pool_entry_;
|
| };
|
|
|
| +// Used to generate IncBlockCounter bytecodes and the {source range, slot}
|
| +// mapping for block coverage.
|
| +class BytecodeGenerator::BlockCoverageBuilder final : public ZoneObject {
|
| + public:
|
| + explicit BlockCoverageBuilder(Zone* zone, BytecodeArrayBuilder* builder)
|
| + : slots_(0, zone), builder_(builder) {}
|
| +
|
| + static const int kNoCoverageArraySlot = -1;
|
| +
|
| + int AllocateBlockCoverageSlot(SourceRange range) {
|
| + if (range.IsEmpty()) return kNoCoverageArraySlot;
|
| + const int slot = static_cast<int>(slots_.size());
|
| + slots_.emplace_back(range);
|
| + return slot;
|
| + }
|
| +
|
| + void IncrementBlockCounter(int coverage_array_slot) {
|
| + if (coverage_array_slot == kNoCoverageArraySlot) return;
|
| + builder_->IncBlockCounter(coverage_array_slot);
|
| + }
|
| +
|
| + const ZoneVector<SourceRange>& slots() const { return slots_; }
|
| +
|
| + private:
|
| + // Contains source range information for allocated block coverage counter
|
| + // slots. Slot i covers range slots_[i].
|
| + ZoneVector<SourceRange> slots_;
|
| + BytecodeArrayBuilder* builder_;
|
| +};
|
| +
|
| class BytecodeGenerator::CurrentScope final {
|
| public:
|
| CurrentScope(BytecodeGenerator* generator, Scope* scope)
|
| @@ -767,6 +797,7 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
|
| closure_scope_(info->scope()),
|
| current_scope_(info->scope()),
|
| globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())),
|
| + block_coverage_builder_(nullptr),
|
| global_declarations_(0, info->zone()),
|
| function_literals_(0, info->zone()),
|
| native_function_literals_(0, info->zone()),
|
| @@ -779,10 +810,23 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
|
| generator_state_(),
|
| loop_depth_(0) {
|
| DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope());
|
| + if (info->is_block_coverage_enabled()) {
|
| + DCHECK(FLAG_block_coverage);
|
| + block_coverage_builder_ =
|
| + new (zone()) BlockCoverageBuilder(zone(), builder());
|
| + }
|
| }
|
|
|
| Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) {
|
| + DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
|
| +
|
| AllocateDeferredConstants(isolate);
|
| +
|
| + if (info()->is_block_coverage_enabled()) {
|
| + info()->set_coverage_info(
|
| + isolate->factory()->NewCoverageInfo(block_coverage_builder_->slots()));
|
| + }
|
| +
|
| if (HasStackOverflow()) return Handle<BytecodeArray>();
|
| return builder()->ToBytecodeArray(isolate);
|
| }
|
| @@ -1184,12 +1228,18 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
|
|
|
| void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
|
| builder()->SetStatementPosition(stmt);
|
| +
|
| + int then_slot = AllocateBlockCoverageSlotIfEnabled(stmt->then_range());
|
| + int else_slot = AllocateBlockCoverageSlotIfEnabled(stmt->else_range());
|
| +
|
| if (stmt->condition()->ToBooleanIsTrue()) {
|
| // Generate then block unconditionally as always true.
|
| + BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
|
| Visit(stmt->then_statement());
|
| } else if (stmt->condition()->ToBooleanIsFalse()) {
|
| // Generate else block unconditionally if it exists.
|
| if (stmt->HasElseStatement()) {
|
| + BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
|
| Visit(stmt->else_statement());
|
| }
|
| } else {
|
| @@ -1202,11 +1252,13 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
|
| TestFallthrough::kThen);
|
|
|
| then_labels.Bind(builder());
|
| + BuildIncrementBlockCoverageCounterIfEnabled(then_slot);
|
| Visit(stmt->then_statement());
|
|
|
| if (stmt->HasElseStatement()) {
|
| builder()->Jump(&end_label);
|
| else_labels.Bind(builder());
|
| + BuildIncrementBlockCoverageCounterIfEnabled(else_slot);
|
| Visit(stmt->else_statement());
|
| } else {
|
| else_labels.Bind(builder());
|
| @@ -3851,6 +3903,19 @@ void BytecodeGenerator::BuildLoadPropertyKey(LiteralProperty* property,
|
| }
|
| }
|
|
|
| +int BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled(SourceRange range) {
|
| + return (block_coverage_builder_ == nullptr)
|
| + ? BlockCoverageBuilder::kNoCoverageArraySlot
|
| + : block_coverage_builder_->AllocateBlockCoverageSlot(range);
|
| +}
|
| +
|
| +void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
|
| + int coverage_array_slot) {
|
| + if (block_coverage_builder_ != nullptr) {
|
| + block_coverage_builder_->IncrementBlockCounter(coverage_array_slot);
|
| + }
|
| +}
|
| +
|
| // Visits the expression |expr| for testing its boolean value and jumping to the
|
| // |then| or |other| label depending on value and short-circuit semantics
|
| void BytecodeGenerator::VisitForTest(Expression* expr,
|
|
|