From 9365d0904eb7e50bfc7ae6640d939fb924440ce2 Mon Sep 17 00:00:00 2001 From: Jakob Gruber Date: Mon, 3 Dec 2018 15:34:35 +0100 Subject: [PATCH] [coverage] Rework continuation counter handling This changes a few bits about how continuation counters are handled. It introduces a new mechanism that allows removal of a continuation range after it has been created. If coverage is enabled, we run a first post-processing pass on the AST immediately after parsing, which removes problematic continuation ranges in two situations: 1. nested continuation counters - only the outermost stays alive. 2. trailing continuation counters within a block-like structure are removed if the containing structure itself has a continuation. R=bmeurer@chromium.org, jgruber@chromium.org, yangguo@chromium.org Bug: v8:8381, v8:8539 Change-Id: I6bcaea5060d8c481d7bae099f6db9f993cc30ee3 Reviewed-on: https://chromium-review.googlesource.com/c/1339119 Reviewed-by: Yang Guo Reviewed-by: Leszek Swirski Reviewed-by: Georg Neis Commit-Queue: Jakob Gruber Cr-Commit-Position: refs/heads/master@{#58443} --- BUILD.gn | 2 + src/ast/ast-source-ranges.h | 83 +++++++++- src/ast/source-range-ast-visitor.cc | 68 ++++++++ src/ast/source-range-ast-visitor.h | 49 ++++++ src/debug/debug-coverage.cc | 22 --- src/interpreter/bytecode-generator.cc | 1 - src/interpreter/control-flow-builders.cc | 2 +- src/interpreter/control-flow-builders.h | 7 - src/parsing/parser.cc | 12 ++ .../cpu-profiler/coverage-block-expected.txt | 138 ++++------------ test/mjsunit/code-coverage-block-opt.js | 4 +- test/mjsunit/code-coverage-block.js | 156 +++++++++++++++--- 12 files changed, 382 insertions(+), 162 deletions(-) create mode 100644 src/ast/source-range-ast-visitor.cc create mode 100644 src/ast/source-range-ast-visitor.h diff --git a/BUILD.gn b/BUILD.gn index 5f4225762e..dde932505b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1668,6 +1668,8 @@ v8_source_set("v8_base") { "src/ast/prettyprinter.h", "src/ast/scopes.cc", "src/ast/scopes.h", + "src/ast/source-range-ast-visitor.cc", + "src/ast/source-range-ast-visitor.h", "src/ast/variables.cc", "src/ast/variables.h", "src/bailout-reason.cc", diff --git a/src/ast/ast-source-ranges.h b/src/ast/ast-source-ranges.h index 60222a4035..a04e68fa2f 100644 --- a/src/ast/ast-source-ranges.h +++ b/src/ast/ast-source-ranges.h @@ -59,6 +59,8 @@ class AstNodeSourceRanges : public ZoneObject { public: virtual ~AstNodeSourceRanges() = default; virtual SourceRange GetRange(SourceRangeKind kind) = 0; + virtual bool HasRange(SourceRangeKind kind) = 0; + virtual void RemoveContinuationRange() { UNREACHABLE(); } }; class BinaryOperationSourceRanges final : public AstNodeSourceRanges { @@ -67,10 +69,14 @@ class BinaryOperationSourceRanges final : public AstNodeSourceRanges { : right_range_(right_range) {} SourceRange GetRange(SourceRangeKind kind) override { - DCHECK_EQ(kind, SourceRangeKind::kRight); + DCHECK(HasRange(kind)); return right_range_; } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kRight; + } + private: SourceRange right_range_; }; @@ -81,10 +87,19 @@ class ContinuationSourceRanges : public AstNodeSourceRanges { : continuation_position_(continuation_position) {} SourceRange GetRange(SourceRangeKind kind) override { - DCHECK_EQ(kind, SourceRangeKind::kContinuation); + DCHECK(HasRange(kind)); return SourceRange::OpenEnded(continuation_position_); } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + continuation_position_ = kNoSourcePosition; + } + private: int32_t continuation_position_; }; @@ -101,10 +116,14 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges { : body_range_(body_range) {} SourceRange GetRange(SourceRangeKind kind) override { - DCHECK_EQ(kind, SourceRangeKind::kBody); + DCHECK(HasRange(kind)); return body_range_; } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kBody; + } + private: SourceRange body_range_; }; @@ -116,6 +135,7 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges { : then_range_(then_range), else_range_(else_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kThen: return then_range_; @@ -126,6 +146,10 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges { } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse; + } + private: SourceRange then_range_; SourceRange else_range_; @@ -138,12 +162,14 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges { : then_range_(then_range), else_range_(else_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kElse: return else_range_; case SourceRangeKind::kThen: return then_range_; case SourceRangeKind::kContinuation: { + if (!has_continuation_) return SourceRange::Empty(); const SourceRange& trailing_range = else_range_.IsEmpty() ? then_range_ : else_range_; return SourceRange::ContinuationOf(trailing_range); @@ -153,9 +179,20 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges { } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse || + kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + has_continuation_ = false; + } + private: SourceRange then_range_; SourceRange else_range_; + bool has_continuation_ = true; }; class IterationStatementSourceRanges final : public AstNodeSourceRanges { @@ -164,18 +201,31 @@ class IterationStatementSourceRanges final : public AstNodeSourceRanges { : body_range_(body_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kBody: return body_range_; case SourceRangeKind::kContinuation: + if (!has_continuation_) return SourceRange::Empty(); return SourceRange::ContinuationOf(body_range_); default: UNREACHABLE(); } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kBody || + kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + has_continuation_ = false; + } + private: SourceRange body_range_; + bool has_continuation_ = true; }; class JumpStatementSourceRanges final : public ContinuationSourceRanges { @@ -200,6 +250,7 @@ class NaryOperationSourceRanges final : public AstNodeSourceRanges { size_t RangeCount() const { return ranges_.size(); } SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); } + bool HasRange(SourceRangeKind kind) override { return false; } private: ZoneVector ranges_; @@ -229,18 +280,31 @@ class TryCatchStatementSourceRanges final : public AstNodeSourceRanges { : catch_range_(catch_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kCatch: return catch_range_; case SourceRangeKind::kContinuation: + if (!has_continuation_) return SourceRange::Empty(); return SourceRange::ContinuationOf(catch_range_); default: UNREACHABLE(); } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kCatch || + kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + has_continuation_ = false; + } + private: SourceRange catch_range_; + bool has_continuation_ = true; }; class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges { @@ -249,18 +313,31 @@ class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges { : finally_range_(finally_range) {} SourceRange GetRange(SourceRangeKind kind) override { + DCHECK(HasRange(kind)); switch (kind) { case SourceRangeKind::kFinally: return finally_range_; case SourceRangeKind::kContinuation: + if (!has_continuation_) return SourceRange::Empty(); return SourceRange::ContinuationOf(finally_range_); default: UNREACHABLE(); } } + bool HasRange(SourceRangeKind kind) override { + return kind == SourceRangeKind::kFinally || + kind == SourceRangeKind::kContinuation; + } + + void RemoveContinuationRange() override { + DCHECK(HasRange(SourceRangeKind::kContinuation)); + has_continuation_ = false; + } + private: SourceRange finally_range_; + bool has_continuation_ = true; }; // Maps ast node pointers to associated source ranges. The parser creates these diff --git a/src/ast/source-range-ast-visitor.cc b/src/ast/source-range-ast-visitor.cc new file mode 100644 index 0000000000..442b23718c --- /dev/null +++ b/src/ast/source-range-ast-visitor.cc @@ -0,0 +1,68 @@ +// Copyright 2018 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. + +#include "src/ast/source-range-ast-visitor.h" + +#include "src/ast/ast-source-ranges.h" + +namespace v8 { +namespace internal { + +SourceRangeAstVisitor::SourceRangeAstVisitor(uintptr_t stack_limit, + Expression* root, + SourceRangeMap* source_range_map) + : AstTraversalVisitor(stack_limit, root), + source_range_map_(source_range_map) {} + +void SourceRangeAstVisitor::VisitBlock(Block* stmt) { + AstTraversalVisitor::VisitBlock(stmt); + ZonePtrList* stmts = stmt->statements(); + AstNodeSourceRanges* enclosingSourceRanges = source_range_map_->Find(stmt); + if (enclosingSourceRanges != nullptr) { + CHECK(enclosingSourceRanges->HasRange(SourceRangeKind::kContinuation)); + MaybeRemoveLastContinuationRange(stmts); + } +} + +void SourceRangeAstVisitor::VisitFunctionLiteral(FunctionLiteral* expr) { + AstTraversalVisitor::VisitFunctionLiteral(expr); + ZonePtrList* stmts = expr->body(); + MaybeRemoveLastContinuationRange(stmts); +} + +bool SourceRangeAstVisitor::VisitNode(AstNode* node) { + AstNodeSourceRanges* range = source_range_map_->Find(node); + + if (range == nullptr) return true; + if (!range->HasRange(SourceRangeKind::kContinuation)) return true; + + // Called in pre-order. In case of conflicting continuation ranges, only the + // outermost range may survive. + + SourceRange continuation = range->GetRange(SourceRangeKind::kContinuation); + if (continuation_positions_.find(continuation.start) != + continuation_positions_.end()) { + range->RemoveContinuationRange(); + } else { + continuation_positions_.emplace(continuation.start); + } + + return true; +} + +void SourceRangeAstVisitor::MaybeRemoveLastContinuationRange( + ZonePtrList* statements) { + if (statements->is_empty()) return; + + Statement* last_statement = statements->last(); + AstNodeSourceRanges* last_range = source_range_map_->Find(last_statement); + if (last_range == nullptr) return; + + if (last_range->HasRange(SourceRangeKind::kContinuation)) { + last_range->RemoveContinuationRange(); + } +} + +} // namespace internal +} // namespace v8 diff --git a/src/ast/source-range-ast-visitor.h b/src/ast/source-range-ast-visitor.h new file mode 100644 index 0000000000..4ea36a947f --- /dev/null +++ b/src/ast/source-range-ast-visitor.h @@ -0,0 +1,49 @@ +// Copyright 2018 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. + +#ifndef V8_AST_SOURCE_RANGE_AST_VISITOR_H_ +#define V8_AST_SOURCE_RANGE_AST_VISITOR_H_ + +#include + +#include "src/ast/ast-traversal-visitor.h" + +namespace v8 { +namespace internal { + +class SourceRangeMap; + +// Post-processes generated source ranges while the AST structure still exists. +// +// In particular, SourceRangeAstVisitor +// +// 1. deduplicates continuation source ranges, only keeping the outermost one. +// See also: https://crbug.com/v8/8539. +// +// 2. removes the source range associated with the final statement in a block +// or function body if the parent itself has a source range associated with it. +// See also: https://crbug.com/v8/8381. +class SourceRangeAstVisitor final + : public AstTraversalVisitor { + public: + SourceRangeAstVisitor(uintptr_t stack_limit, Expression* root, + SourceRangeMap* source_range_map); + + private: + friend class AstTraversalVisitor; + + void VisitBlock(Block* stmt); + void VisitFunctionLiteral(FunctionLiteral* expr); + bool VisitNode(AstNode* node); + + void MaybeRemoveLastContinuationRange(ZonePtrList* stmts); + + SourceRangeMap* source_range_map_ = nullptr; + std::unordered_set continuation_positions_; +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_AST_SOURCE_RANGE_AST_VISITOR_H_ diff --git a/src/debug/debug-coverage.cc b/src/debug/debug-coverage.cc index ae2a5049c5..e15ebaab6a 100644 --- a/src/debug/debug-coverage.cc +++ b/src/debug/debug-coverage.cc @@ -233,25 +233,6 @@ bool HaveSameSourceRange(const CoverageBlock& lhs, const CoverageBlock& rhs) { return lhs.start == rhs.start && lhs.end == rhs.end; } -void MergeDuplicateSingletons(CoverageFunction* function) { - CoverageBlockIterator iter(function); - - while (iter.Next() && iter.HasNext()) { - CoverageBlock& block = iter.GetBlock(); - CoverageBlock& next_block = iter.GetNextBlock(); - - // Identical ranges should only occur through singleton ranges. Consider the - // ranges for `for (.) break;`: continuation ranges for both the `break` and - // `for` statements begin after the trailing semicolon. - // Such ranges are merged and keep the maximal execution count. - if (!HaveSameSourceRange(block, next_block)) continue; - - DCHECK_EQ(kNoSourcePosition, block.end); // Singleton range. - next_block.count = std::max(block.count, next_block.count); - iter.DeleteBlock(); - } -} - void MergeDuplicateRanges(CoverageFunction* function) { CoverageBlockIterator iter(function); @@ -424,9 +405,6 @@ void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info, // If in binary mode, only report counts of 0/1. if (mode == debug::Coverage::kBlockBinary) ClampToBinary(function); - // Remove duplicate singleton ranges, keeping the max count. - MergeDuplicateSingletons(function); - // Remove singleton ranges with the same start position as a full range and // throw away their counts. // Singleton ranges are only intended to split existing full ranges and should diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index 47d018a154..6663ab6228 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -368,7 +368,6 @@ class BytecodeGenerator::ControlScopeForBreakable final protected: bool Execute(Command command, Statement* statement, int source_position) override { - control_builder_->set_needs_continuation_counter(); if (statement != statement_) return false; switch (command) { case CMD_BREAK: diff --git a/src/interpreter/control-flow-builders.cc b/src/interpreter/control-flow-builders.cc index bada935e4a..6b1bdc3424 100644 --- a/src/interpreter/control-flow-builders.cc +++ b/src/interpreter/control-flow-builders.cc @@ -13,7 +13,7 @@ namespace interpreter { BreakableControlFlowBuilder::~BreakableControlFlowBuilder() { BindBreakTarget(); DCHECK(break_labels_.empty() || break_labels_.is_bound()); - if (block_coverage_builder_ != nullptr && needs_continuation_counter()) { + if (block_coverage_builder_ != nullptr) { block_coverage_builder_->IncrementBlockCounter( node_, SourceRangeKind::kContinuation); } diff --git a/src/interpreter/control-flow-builders.h b/src/interpreter/control-flow-builders.h index fdc57776a8..8359f0d1ee 100644 --- a/src/interpreter/control-flow-builders.h +++ b/src/interpreter/control-flow-builders.h @@ -58,11 +58,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder BytecodeLabels* break_labels() { return &break_labels_; } - void set_needs_continuation_counter() { needs_continuation_counter_ = true; } - bool needs_continuation_counter() const { - return needs_continuation_counter_; - } - protected: void EmitJump(BytecodeLabels* labels); void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode, @@ -81,7 +76,6 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder // A continuation counter (for block coverage) is needed e.g. when // encountering a break statement. AstNode* node_; - bool needs_continuation_counter_ = false; BlockCoverageBuilder* block_coverage_builder_; }; @@ -107,7 +101,6 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder { : BreakableControlFlowBuilder(builder, block_coverage_builder, node), continue_labels_(builder->zone()) { if (block_coverage_builder_ != nullptr) { - set_needs_continuation_counter(); block_coverage_body_slot_ = block_coverage_builder_->AllocateBlockCoverageSlot( node, SourceRangeKind::kBody); diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc index 6c8ced7fc1..aa745a0553 100644 --- a/src/parsing/parser.cc +++ b/src/parsing/parser.cc @@ -10,6 +10,7 @@ #include "src/ast/ast-function-literal-id-reindexer.h" #include "src/ast/ast-traversal-visitor.h" #include "src/ast/ast.h" +#include "src/ast/source-range-ast-visitor.h" #include "src/bailout-reason.h" #include "src/base/platform/platform.h" #include "src/char-predicates-inl.h" @@ -462,6 +463,15 @@ void MaybeResetCharacterStream(ParseInfo* info, FunctionLiteral* literal) { info->ResetCharacterStream(); } +void MaybeProcessSourceRanges(ParseInfo* parse_info, Expression* root, + uintptr_t stack_limit_) { + if (root != nullptr && parse_info->source_range_map() != nullptr) { + SourceRangeAstVisitor visitor(stack_limit_, root, + parse_info->source_range_map()); + visitor.Run(); + } +} + } // namespace FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { @@ -485,6 +495,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { scanner_.Initialize(); FunctionLiteral* result = DoParseProgram(isolate, info); MaybeResetCharacterStream(info, result); + MaybeProcessSourceRanges(info, result, stack_limit_); HandleSourceURLComments(isolate, info->script()); @@ -673,6 +684,7 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, FunctionLiteral* result = DoParseFunction(isolate, info, info->function_name()); MaybeResetCharacterStream(info, result); + MaybeProcessSourceRanges(info, result, stack_limit_); if (result != nullptr) { Handle inferred_name(shared_info->inferred_name(), isolate); result->set_inferred_name(inferred_name); diff --git a/test/inspector/cpu-profiler/coverage-block-expected.txt b/test/inspector/cpu-profiler/coverage-block-expected.txt index a631e72c69..cc48cfa85b 100644 --- a/test/inspector/cpu-profiler/coverage-block-expected.txt +++ b/test/inspector/cpu-profiler/coverage-block-expected.txt @@ -34,7 +34,7 @@ Running test: testPreciseCountCoverage [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -60,13 +60,8 @@ Running test: testPreciseCountCoverage } [2] : { count : 7 - endOffset : 71 - startOffset : 41 - } - [3] : { - count : 0 endOffset : 72 - startOffset : 71 + startOffset : 41 } ] } @@ -90,11 +85,6 @@ Running test: testPreciseCountCoverage endOffset : 208 startOffset : 177 } - [1] : { - count : 0 - endOffset : 207 - startOffset : 206 - } ] } ] @@ -104,7 +94,7 @@ Running test: testPreciseCountCoverage [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -116,7 +106,7 @@ Running test: testPreciseCountCoverage } ] scriptId : - url : + url : } ] } @@ -147,7 +137,7 @@ Running test: testPreciseCountCoverageIncremental [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -173,13 +163,8 @@ Running test: testPreciseCountCoverageIncremental } [2] : { count : 7 - endOffset : 71 - startOffset : 41 - } - [3] : { - count : 0 endOffset : 72 - startOffset : 71 + startOffset : 41 } ] } @@ -203,11 +188,6 @@ Running test: testPreciseCountCoverageIncremental endOffset : 208 startOffset : 177 } - [1] : { - count : 0 - endOffset : 207 - startOffset : 206 - } ] } ] @@ -267,13 +247,8 @@ Running test: testPreciseCountCoverageIncremental } [2] : { count : 10945 - endOffset : 71 - startOffset : 41 - } - [3] : { - count : 0 endOffset : 72 - startOffset : 71 + startOffset : 41 } ] } @@ -291,11 +266,6 @@ Running test: testPreciseCountCoverageIncremental endOffset : 156 startOffset : 143 } - [2] : { - count : 0 - endOffset : 174 - startOffset : 173 - } ] } ] @@ -305,7 +275,7 @@ Running test: testPreciseCountCoverageIncremental [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -317,12 +287,12 @@ Running test: testPreciseCountCoverageIncremental } ] scriptId : - url : + url : } [2] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -334,7 +304,7 @@ Running test: testPreciseCountCoverageIncremental } ] scriptId : - url : + url : } ] } @@ -403,7 +373,7 @@ Running test: testBestEffortCoverageWithPreciseBinaryEnabled [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -453,7 +423,7 @@ Running test: testBestEffortCoverageWithPreciseBinaryEnabled [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -465,7 +435,7 @@ Running test: testBestEffortCoverageWithPreciseBinaryEnabled } ] scriptId : - url : + url : } ] } @@ -477,7 +447,7 @@ Running test: testBestEffortCoverageWithPreciseBinaryEnabled [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -527,7 +497,7 @@ Running test: testBestEffortCoverageWithPreciseBinaryEnabled [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -539,7 +509,7 @@ Running test: testBestEffortCoverageWithPreciseBinaryEnabled } ] scriptId : - url : + url : } ] } @@ -563,7 +533,7 @@ Running test: testBestEffortCoverageWithPreciseCountEnabled [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -613,7 +583,7 @@ Running test: testBestEffortCoverageWithPreciseCountEnabled [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -625,7 +595,7 @@ Running test: testBestEffortCoverageWithPreciseCountEnabled } ] scriptId : - url : + url : } ] } @@ -637,7 +607,7 @@ Running test: testBestEffortCoverageWithPreciseCountEnabled [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -687,7 +657,7 @@ Running test: testBestEffortCoverageWithPreciseCountEnabled [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : false ranges : [ [0] : { @@ -699,7 +669,7 @@ Running test: testBestEffortCoverageWithPreciseCountEnabled } ] scriptId : - url : + url : } ] } @@ -721,7 +691,7 @@ Running test: testEnablePreciseCountCoverageAtPause [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -733,7 +703,7 @@ Running test: testEnablePreciseCountCoverageAtPause } ] scriptId : - url : + url : } ] } @@ -757,7 +727,7 @@ Running test: testPreciseBinaryCoverage [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -776,11 +746,6 @@ Running test: testPreciseBinaryCoverage endOffset : 73 startOffset : 1 } - [1] : { - count : 0 - endOffset : 72 - startOffset : 71 - } ] } [2] : { @@ -803,11 +768,6 @@ Running test: testPreciseBinaryCoverage endOffset : 208 startOffset : 177 } - [1] : { - count : 0 - endOffset : 207 - startOffset : 206 - } ] } ] @@ -862,7 +822,7 @@ Running test: testPreciseBinaryCoverage } [1] : { count : 1 - endOffset : 71 + endOffset : 72 startOffset : 32 } ] @@ -876,11 +836,6 @@ Running test: testPreciseBinaryCoverage endOffset : 175 startOffset : 74 } - [1] : { - count : 0 - endOffset : 174 - startOffset : 173 - } ] } ] @@ -890,7 +845,7 @@ Running test: testPreciseBinaryCoverage [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -902,12 +857,12 @@ Running test: testPreciseBinaryCoverage } ] scriptId : - url : + url : } [2] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -919,7 +874,7 @@ Running test: testPreciseBinaryCoverage } ] scriptId : - url : + url : } ] } @@ -950,7 +905,7 @@ Running test: testPreciseCountCoveragePartial [0] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -969,11 +924,6 @@ Running test: testPreciseCountCoveragePartial endOffset : 224 startOffset : 10 } - [1] : { - count : 0 - endOffset : 223 - startOffset : 222 - } ] } [2] : { @@ -985,11 +935,6 @@ Running test: testPreciseCountCoveragePartial endOffset : 176 startOffset : 31 } - [1] : { - count : 0 - endOffset : 175 - startOffset : 172 - } ] } [3] : { @@ -1001,11 +946,6 @@ Running test: testPreciseCountCoveragePartial endOffset : 172 startOffset : 64 } - [1] : { - count : 0 - endOffset : 171 - startOffset : 166 - } ] } [4] : { @@ -1017,11 +957,6 @@ Running test: testPreciseCountCoveragePartial endOffset : 166 startOffset : 99 } - [1] : { - count : 0 - endOffset : 165 - startOffset : 158 - } ] } [5] : { @@ -1068,11 +1003,6 @@ Running test: testPreciseCountCoveragePartial endOffset : 172 startOffset : 64 } - [1] : { - count : 0 - endOffset : 171 - startOffset : 166 - } ] } [1] : { @@ -1093,7 +1023,7 @@ Running test: testPreciseCountCoveragePartial [1] : { functions : [ [0] : { - functionName : + functionName : isBlockCoverage : true ranges : [ [0] : { @@ -1105,7 +1035,7 @@ Running test: testPreciseCountCoveragePartial } ] scriptId : - url : + url : } ] } diff --git a/test/mjsunit/code-coverage-block-opt.js b/test/mjsunit/code-coverage-block-opt.js index bd721d52f1..ee21ff6a80 100644 --- a/test/mjsunit/code-coverage-block-opt.js +++ b/test/mjsunit/code-coverage-block-opt.js @@ -23,7 +23,7 @@ f(); f(); f(); f(); f(); f(); // 0150 `, [{"start":0,"end":199,"count":1}, {"start":0,"end":33,"count":4}, // TODO(jgruber): Invocation count is off. - {"start":25,"end":32,"count":16}, + {"start":25,"end":31,"count":16}, {"start":50,"end":76,"count":2}] // TODO(jgruber): Invocation count is off. ); @@ -45,7 +45,7 @@ TestCoverage("Partial coverage collection", }(); // 0400 `, [{"start":52,"end":153,"count":0}, - {"start":121,"end":152,"count":1}] + {"start":121,"end":137,"count":1}] ); %DebugToggleBlockCoverage(false); diff --git a/test/mjsunit/code-coverage-block.js b/test/mjsunit/code-coverage-block.js index c3d775aa27..0547d54a42 100644 --- a/test/mjsunit/code-coverage-block.js +++ b/test/mjsunit/code-coverage-block.js @@ -246,8 +246,7 @@ function g() {} // 0000 {"start":224,"end":237,"count":12}, {"start":273,"end":277,"count":0}, {"start":412,"end":416,"count":12}, - {"start":462,"end":475,"count":12}, - {"start":620,"end":622,"count":0}] + {"start":462,"end":475,"count":12}] ); TestCoverage( @@ -357,7 +356,7 @@ TestCoverage( {"start":219,"end":222,"count":0}, {"start":254,"end":274,"count":0}, {"start":369,"end":372,"count":0}, - {"start":390,"end":404,"count":0}, + {"start":403,"end":404,"count":0}, {"start":513,"end":554,"count":0}] ); @@ -376,10 +375,10 @@ TestCoverage("try/catch/finally statements with early return", [{"start":0,"end":449,"count":1}, {"start":1,"end":151,"count":1}, {"start":67,"end":70,"count":0}, - {"start":89,"end":150,"count":0}, + {"start":91,"end":150,"count":0}, {"start":201,"end":401,"count":1}, {"start":267,"end":270,"count":0}, - {"start":319,"end":400,"count":0}] + {"start":321,"end":400,"count":0}] ); TestCoverage( @@ -411,11 +410,11 @@ TestCoverage( [{"start":0,"end":1099,"count":1}, {"start":1,"end":151,"count":1}, {"start":67,"end":70,"count":0}, - {"start":89,"end":150,"count":0}, + {"start":91,"end":150,"count":0}, {"start":201,"end":351,"count":1}, - {"start":284,"end":350,"count":0}, + {"start":286,"end":350,"count":0}, {"start":401,"end":701,"count":1}, - {"start":569,"end":700,"count":0}, + {"start":603,"end":700,"count":0}, {"start":561,"end":568,"count":0}, // TODO(jgruber): Sorting. {"start":751,"end":1051,"count":1}, {"start":817,"end":820,"count":0}, @@ -437,7 +436,7 @@ TestCoverage( [{"start":0,"end":399,"count":1}, {"start":1,"end":351,"count":1}, {"start":154,"end":204,"count":0}, - {"start":226,"end":303,"count":0}] + {"start":226,"end":350,"count":0}] ); TestCoverage( @@ -467,11 +466,7 @@ TestCoverage( [{"start":0,"end":999,"count":1}, {"start":1,"end":951,"count":1}, {"start":152,"end":202,"count":0}, - {"start":285,"end":353,"count":0}, - {"start":472,"end":503,"count":0}, - {"start":626,"end":653,"count":0}, - {"start":768,"end":803,"count":0}, - {"start":867,"end":869,"count":0}] + {"start":285,"end":353,"count":0}] ); TestCoverage( @@ -496,11 +491,8 @@ TestCoverage( [{"start":0,"end":749,"count":1}, {"start":1,"end":701,"count":1}, {"start":87,"end":153,"count":2}, - {"start":125,"end":153,"count":0}, {"start":271,"end":403,"count":2}, - {"start":379,"end":403,"count":0}, - {"start":509,"end":653,"count":2}, - {"start":621,"end":653,"count":0}] + {"start":509,"end":653,"count":2}] ); TestCoverage( @@ -570,6 +562,7 @@ try { // 0200 } catch (e) {} // 0450 `, [{"start":0,"end":499,"count":1}, + {"start":451,"end":452,"count":0}, {"start":12,"end":101,"count":3}, {"start":60,"end":100,"count":0}, {"start":264,"end":353,"count":3}, @@ -648,6 +641,7 @@ try { // 0200 } catch (e) {} // 0450 `, [{"start":0,"end":499,"count":1}, + {"start":451,"end":452,"count":0}, {"start":12,"end":101,"count":3}, {"start":65,"end":100,"count":0}, {"start":264,"end":353,"count":3}, @@ -846,8 +840,7 @@ Util.escape("foo.bar"); // 0400 `, [{"start":0,"end":449,"count":1}, {"start":64,"end":351,"count":1}, - {"start":112,"end":203,"count":0}, - {"start":268,"end":350,"count":0}] + {"start":112,"end":203,"count":0}] ); TestCoverage( @@ -879,17 +872,136 @@ TestCoverage( {"start":1,"end":151,"count":1}, {"start":118,"end":137,"count":0}, {"start":201,"end":351,"count":1}, - {"start":277,"end":318,"count":0}, + {"start":279,"end":318,"count":0}, {"start":401,"end":525,"count":1}, {"start":475,"end":486,"count":0}, {"start":503,"end":523,"count":0}, {"start":551,"end":651,"count":1}, {"start":622,"end":639,"count":0}, {"start":701,"end":801,"count":1}, - {"start":773,"end":791,"count":0}, + {"start":774,"end":791,"count":0}, {"start":851,"end":1001,"count":1}, {"start":920,"end":928,"count":0}, {"start":929,"end":965,"count":0}] ); +TestCoverage( +"terminal break statement", +` +while (true) { // 0000 + const b = false // 0050 + break // 0100 +} // 0150 +let stop = false // 0200 +while (true) { // 0250 + if (stop) { // 0300 + break // 0350 + } // 0400 + stop = true // 0450 +} // 0500 +`, +[{"start":0,"end":549,"count":1}, + {"start":263,"end":501,"count":2}, + {"start":312,"end":501,"count":1}] +); + +TestCoverage( +"terminal return statement", +` +function a () { // 0000 + const b = false // 0050 + return 1 // 0100 +} // 0150 +const b = (early) => { // 0200 + if (early) { // 0250 + return 2 // 0300 + } // 0350 + return 3 // 0400 +} // 0450 +const c = () => { // 0500 + if (true) { // 0550 + return // 0600 + } // 0650 +} // 0700 +a(); b(false); b(true); c() // 0750 +`, +[{"start":0,"end":799,"count":1}, + {"start":0,"end":151,"count":1}, + {"start":210,"end":451,"count":2}, + {"start":263,"end":450,"count":1}, + {"start":510,"end":701,"count":1}] +); + +TestCoverage( +"terminal blocks", +` +function a () { // 0000 + { // 0050 + return 'a' // 0100 + } // 0150 +} // 0200 +function b () { // 0250 + { // 0300 + { // 0350 + return 'b' // 0400 + } // 0450 + } // 0500 +} // 0550 +a(); b() // 0600 +`, +[{"start":0,"end":649,"count":1}, + {"start":0,"end":201,"count":1}, + {"start":250,"end":551,"count":1}] +); + +TestCoverage( +"terminal if statements", +` +function a (branch) { // 0000 + if (branch) { // 0050 + return 'a' // 0100 + } else { // 0150 + return 'b' // 0200 + } // 0250 +} // 0300 +function b (branch) { // 0350 + if (branch) { // 0400 + if (branch) { // 0450 + return 'c' // 0500 + } // 0550 + } // 0600 +} // 0650 +function c (branch) { // 0700 + if (branch) { // 0750 + return 'c' // 0800 + } else { // 0850 + return 'd' // 0900 + } // 0950 +} // 1000 +function d (branch) { // 1050 + if (branch) { // 1100 + if (!branch) { // 1150 + return 'e' // 1200 + } else { // 1250 + return 'f' // 1300 + } // 1350 + } else { // 1400 + // noop // 1450 + } // 1500 +} // 1550 +a(true); a(false); b(true); b(false) // 1600 +c(true); d(true); // 1650 +`, +[{"start":0,"end":1699,"count":1}, + {"start":0,"end":301,"count":2}, + {"start":64,"end":253,"count":1}, + {"start":350,"end":651,"count":2}, + {"start":414,"end":603,"count":1}, + {"start":700,"end":1001,"count":1}, + {"start":853,"end":953,"count":0}, + {"start":1050,"end":1551,"count":1}, + {"start":1167,"end":1255,"count":0}, + {"start":1403,"end":1503,"count":0}] +); + %DebugToggleBlockCoverage(false);