[coverage] Add dedicated FunctionLiteral counters
Prior to this CL, call counts at function scope were taken from the FeedbackVector::invocation_count field. This had two major drawbacks: 1. for generator functions, these count the number of resumptions instead of the number of calls; and 2. the invocation count is not maintained in optimized code. The solution implemented here is to add a dedicated call counter at function scope which is incremented exactly once each time the function is called. A minor complication is that our coverage output format expects function-scope counts in the dedicated CoverageFunction object, and not as a CoverageBlock. Thus function-scope block counts are initially marked with magic positions, and later recognized and rewritten during processing. This CL thus fixes reported generator function call counts and enables optimizations in block coverage modes (more to come in a follow-up). Drive-by: Don't report functions with empty source ranges. Bug: v8:6000,v8:9148,v8:9212 Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng Change-Id: Idbe5edb35a595cf12b6649314738ac00efd173b8 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1613996 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#61574}
This commit is contained in:
parent
3cb560adfe
commit
3002ff44ee
@ -25,6 +25,18 @@ struct SourceRange {
|
|||||||
int end = kNoSourcePosition) {
|
int end = kNoSourcePosition) {
|
||||||
return that.IsEmpty() ? Empty() : SourceRange(that.end, end);
|
return that.IsEmpty() ? Empty() : SourceRange(that.end, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr int kFunctionLiteralSourcePosition = -2;
|
||||||
|
STATIC_ASSERT(kFunctionLiteralSourcePosition == kNoSourcePosition - 1);
|
||||||
|
|
||||||
|
// Source ranges associated with a function literal do not contain real
|
||||||
|
// source positions; instead, they are created with special marker values.
|
||||||
|
// These are later recognized and rewritten during processing in
|
||||||
|
// Coverage::Collect().
|
||||||
|
static SourceRange FunctionLiteralMarkerRange() {
|
||||||
|
return {kFunctionLiteralSourcePosition, kFunctionLiteralSourcePosition};
|
||||||
|
}
|
||||||
|
|
||||||
int32_t start, end;
|
int32_t start, end;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,6 +47,7 @@ struct SourceRange {
|
|||||||
V(Block) \
|
V(Block) \
|
||||||
V(CaseClause) \
|
V(CaseClause) \
|
||||||
V(Conditional) \
|
V(Conditional) \
|
||||||
|
V(FunctionLiteral) \
|
||||||
V(IfStatement) \
|
V(IfStatement) \
|
||||||
V(IterationStatement) \
|
V(IterationStatement) \
|
||||||
V(JumpStatement) \
|
V(JumpStatement) \
|
||||||
@ -155,6 +168,18 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges {
|
|||||||
SourceRange else_range_;
|
SourceRange else_range_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FunctionLiteralSourceRanges final : public AstNodeSourceRanges {
|
||||||
|
public:
|
||||||
|
SourceRange GetRange(SourceRangeKind kind) override {
|
||||||
|
DCHECK(HasRange(kind));
|
||||||
|
return SourceRange::FunctionLiteralMarkerRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasRange(SourceRangeKind kind) override {
|
||||||
|
return kind == SourceRangeKind::kBody;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class IfStatementSourceRanges final : public AstNodeSourceRanges {
|
class IfStatementSourceRanges final : public AstNodeSourceRanges {
|
||||||
public:
|
public:
|
||||||
explicit IfStatementSourceRanges(const SourceRange& then_range,
|
explicit IfStatementSourceRanges(const SourceRange& then_range,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "src/debug/debug-coverage.h"
|
#include "src/debug/debug-coverage.h"
|
||||||
|
|
||||||
|
#include "src/ast/ast-source-ranges.h"
|
||||||
#include "src/ast/ast.h"
|
#include "src/ast/ast.h"
|
||||||
#include "src/base/hashmap.h"
|
#include "src/base/hashmap.h"
|
||||||
#include "src/debug/debug.h"
|
#include "src/debug/debug.h"
|
||||||
@ -103,11 +104,7 @@ std::vector<CoverageBlock> GetSortedBlockData(SharedFunctionInfo shared) {
|
|||||||
class CoverageBlockIterator final {
|
class CoverageBlockIterator final {
|
||||||
public:
|
public:
|
||||||
explicit CoverageBlockIterator(CoverageFunction* function)
|
explicit CoverageBlockIterator(CoverageFunction* function)
|
||||||
: function_(function),
|
: function_(function) {
|
||||||
ended_(false),
|
|
||||||
delete_current_(false),
|
|
||||||
read_index_(-1),
|
|
||||||
write_index_(-1) {
|
|
||||||
DCHECK(std::is_sorted(function_->blocks.begin(), function_->blocks.end(),
|
DCHECK(std::is_sorted(function_->blocks.begin(), function_->blocks.end(),
|
||||||
CompareCoverageBlock));
|
CompareCoverageBlock));
|
||||||
}
|
}
|
||||||
@ -223,10 +220,10 @@ class CoverageBlockIterator final {
|
|||||||
|
|
||||||
CoverageFunction* function_;
|
CoverageFunction* function_;
|
||||||
std::vector<CoverageBlock> nesting_stack_;
|
std::vector<CoverageBlock> nesting_stack_;
|
||||||
bool ended_;
|
bool ended_ = false;
|
||||||
bool delete_current_;
|
bool delete_current_ = false;
|
||||||
int read_index_;
|
int read_index_ = -1;
|
||||||
int write_index_;
|
int write_index_ = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HaveSameSourceRange(const CoverageBlock& lhs, const CoverageBlock& rhs) {
|
bool HaveSameSourceRange(const CoverageBlock& lhs, const CoverageBlock& rhs) {
|
||||||
@ -312,6 +309,30 @@ void MergeNestedRanges(CoverageFunction* function) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RewriteFunctionScopeCounter(CoverageFunction* function) {
|
||||||
|
// Every function must have at least the top-level function counter.
|
||||||
|
DCHECK(!function->blocks.empty());
|
||||||
|
|
||||||
|
CoverageBlockIterator iter(function);
|
||||||
|
if (iter.Next()) {
|
||||||
|
DCHECK(iter.IsTopLevel());
|
||||||
|
|
||||||
|
CoverageBlock& block = iter.GetBlock();
|
||||||
|
if (block.start == SourceRange::kFunctionLiteralSourcePosition &&
|
||||||
|
block.end == SourceRange::kFunctionLiteralSourcePosition) {
|
||||||
|
// If a function-scope block exists, overwrite the function count. It has
|
||||||
|
// a more reliable count than what we get from the FeedbackVector (which
|
||||||
|
// is imprecise e.g. for generator functions and optimized code).
|
||||||
|
function->count = block.count;
|
||||||
|
|
||||||
|
// Then delete it; for compatibility with non-block coverage modes, the
|
||||||
|
// function-scope block is expected in CoverageFunction, not as a
|
||||||
|
// CoverageBlock.
|
||||||
|
iter.DeleteBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FilterAliasedSingletons(CoverageFunction* function) {
|
void FilterAliasedSingletons(CoverageFunction* function) {
|
||||||
CoverageBlockIterator iter(function);
|
CoverageBlockIterator iter(function);
|
||||||
|
|
||||||
@ -395,16 +416,32 @@ bool IsBinaryMode(debug::CoverageMode mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info,
|
void CollectBlockCoverageInternal(CoverageFunction* function,
|
||||||
|
SharedFunctionInfo info,
|
||||||
debug::CoverageMode mode) {
|
debug::CoverageMode mode) {
|
||||||
DCHECK(IsBlockMode(mode));
|
DCHECK(IsBlockMode(mode));
|
||||||
|
|
||||||
|
// Functions with empty source ranges are not interesting to report. This can
|
||||||
|
// happen e.g. for internally-generated functions like class constructors.
|
||||||
|
if (!function->HasNonEmptySourceRange()) return;
|
||||||
|
|
||||||
function->has_block_coverage = true;
|
function->has_block_coverage = true;
|
||||||
function->blocks = GetSortedBlockData(info);
|
function->blocks = GetSortedBlockData(info);
|
||||||
|
|
||||||
// If in binary mode, only report counts of 0/1.
|
// If in binary mode, only report counts of 0/1.
|
||||||
if (mode == debug::CoverageMode::kBlockBinary) ClampToBinary(function);
|
if (mode == debug::CoverageMode::kBlockBinary) ClampToBinary(function);
|
||||||
|
|
||||||
|
// To stay compatible with non-block coverage modes, the function-scope count
|
||||||
|
// is expected to be in the CoverageFunction, not as part of its blocks.
|
||||||
|
// This finds the function-scope counter, overwrites CoverageFunction::count,
|
||||||
|
// and removes it from the block list.
|
||||||
|
//
|
||||||
|
// Important: Must be called before other transformation passes.
|
||||||
|
RewriteFunctionScopeCounter(function);
|
||||||
|
|
||||||
|
// Functions without blocks don't need to be processed further.
|
||||||
|
if (!function->HasBlocks()) return;
|
||||||
|
|
||||||
// Remove singleton ranges with the same start position as a full range and
|
// Remove singleton ranges with the same start position as a full range and
|
||||||
// throw away their counts.
|
// throw away their counts.
|
||||||
// Singleton ranges are only intended to split existing full ranges and should
|
// Singleton ranges are only intended to split existing full ranges and should
|
||||||
@ -435,6 +472,11 @@ void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info,
|
|||||||
|
|
||||||
// Filter out ranges of zero length.
|
// Filter out ranges of zero length.
|
||||||
FilterEmptyRanges(function);
|
FilterEmptyRanges(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info,
|
||||||
|
debug::CoverageMode mode) {
|
||||||
|
CollectBlockCoverageInternal(function, info, mode);
|
||||||
|
|
||||||
// Reset all counters on the DebugInfo to zero.
|
// Reset all counters on the DebugInfo to zero.
|
||||||
ResetAllBlockCounts(info);
|
ResetAllBlockCounts(info);
|
||||||
@ -589,12 +631,17 @@ std::unique_ptr<Coverage> Coverage::Collect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only include a function range if itself or its parent function is
|
// Only include a function range if itself or its parent function is
|
||||||
// covered, or if it contains non-trivial block coverage.
|
// covered, or if it contains non-trivial block coverage. It must also
|
||||||
|
// have a non-empty source range (otherwise it is not interesting to
|
||||||
|
// report).
|
||||||
bool is_covered = (count != 0);
|
bool is_covered = (count != 0);
|
||||||
bool parent_is_covered =
|
bool parent_is_covered =
|
||||||
(!nesting.empty() && functions->at(nesting.back()).count != 0);
|
(!nesting.empty() && functions->at(nesting.back()).count != 0);
|
||||||
bool has_block_coverage = !function.blocks.empty();
|
bool has_block_coverage = !function.blocks.empty();
|
||||||
if (is_covered || parent_is_covered || has_block_coverage) {
|
bool function_is_relevant =
|
||||||
|
(is_covered || parent_is_covered || has_block_coverage);
|
||||||
|
|
||||||
|
if (function.HasNonEmptySourceRange() && function_is_relevant) {
|
||||||
nesting.push_back(functions->size());
|
nesting.push_back(functions->size());
|
||||||
functions->emplace_back(function);
|
functions->emplace_back(function);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ class Isolate;
|
|||||||
struct CoverageBlock {
|
struct CoverageBlock {
|
||||||
CoverageBlock(int s, int e, uint32_t c) : start(s), end(e), count(c) {}
|
CoverageBlock(int s, int e, uint32_t c) : start(s), end(e), count(c) {}
|
||||||
CoverageBlock() : CoverageBlock(kNoSourcePosition, kNoSourcePosition, 0) {}
|
CoverageBlock() : CoverageBlock(kNoSourcePosition, kNoSourcePosition, 0) {}
|
||||||
|
|
||||||
int start;
|
int start;
|
||||||
int end;
|
int end;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
@ -28,6 +29,10 @@ struct CoverageBlock {
|
|||||||
struct CoverageFunction {
|
struct CoverageFunction {
|
||||||
CoverageFunction(int s, int e, uint32_t c, Handle<String> n)
|
CoverageFunction(int s, int e, uint32_t c, Handle<String> n)
|
||||||
: start(s), end(e), count(c), name(n), has_block_coverage(false) {}
|
: start(s), end(e), count(c), name(n), has_block_coverage(false) {}
|
||||||
|
|
||||||
|
bool HasNonEmptySourceRange() const { return start < end && start >= 0; }
|
||||||
|
bool HasBlocks() const { return !blocks.empty(); }
|
||||||
|
|
||||||
int start;
|
int start;
|
||||||
int end;
|
int end;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
|
@ -1128,7 +1128,8 @@ void BytecodeGenerator::GenerateBytecodeBody() {
|
|||||||
|
|
||||||
// Create a generator object if necessary and initialize the
|
// Create a generator object if necessary and initialize the
|
||||||
// {.generator_object} variable.
|
// {.generator_object} variable.
|
||||||
if (IsResumableFunction(info()->literal()->kind())) {
|
FunctionLiteral* literal = info()->literal();
|
||||||
|
if (IsResumableFunction(literal->kind())) {
|
||||||
BuildGeneratorObjectVariableInitialization();
|
BuildGeneratorObjectVariableInitialization();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1146,6 +1147,9 @@ void BytecodeGenerator::GenerateBytecodeBody() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increment the function-scope block coverage counter.
|
||||||
|
BuildIncrementBlockCoverageCounterIfEnabled(literal, SourceRangeKind::kBody);
|
||||||
|
|
||||||
// Visit declarations within the function scope.
|
// Visit declarations within the function scope.
|
||||||
VisitDeclarations(closure_scope()->declarations());
|
VisitDeclarations(closure_scope()->declarations());
|
||||||
|
|
||||||
@ -1153,22 +1157,22 @@ void BytecodeGenerator::GenerateBytecodeBody() {
|
|||||||
VisitModuleNamespaceImports();
|
VisitModuleNamespaceImports();
|
||||||
|
|
||||||
// Perform a stack-check before the body.
|
// Perform a stack-check before the body.
|
||||||
builder()->StackCheck(info()->literal()->start_position());
|
builder()->StackCheck(literal->start_position());
|
||||||
|
|
||||||
// The derived constructor case is handled in VisitCallSuper.
|
// The derived constructor case is handled in VisitCallSuper.
|
||||||
if (IsBaseConstructor(function_kind())) {
|
if (IsBaseConstructor(function_kind())) {
|
||||||
if (info()->literal()->requires_brand_initialization()) {
|
if (literal->requires_brand_initialization()) {
|
||||||
BuildPrivateBrandInitialization(builder()->Receiver());
|
BuildPrivateBrandInitialization(builder()->Receiver());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info()->literal()->requires_instance_members_initializer()) {
|
if (literal->requires_instance_members_initializer()) {
|
||||||
BuildInstanceMemberInitialization(Register::function_closure(),
|
BuildInstanceMemberInitialization(Register::function_closure(),
|
||||||
builder()->Receiver());
|
builder()->Receiver());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit statements in the function body.
|
// Visit statements in the function body.
|
||||||
VisitStatements(info()->literal()->body());
|
VisitStatements(literal->body());
|
||||||
|
|
||||||
// Emit an implicit return instruction in case control flow can fall off the
|
// Emit an implicit return instruction in case control flow can fall off the
|
||||||
// end of the function without an explicit return being present on all paths.
|
// end of the function without an explicit return being present on all paths.
|
||||||
|
@ -4177,6 +4177,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
|
|||||||
function_literal->set_function_token_position(
|
function_literal->set_function_token_position(
|
||||||
formal_parameters.scope->start_position());
|
formal_parameters.scope->start_position());
|
||||||
|
|
||||||
|
impl()->RecordFunctionLiteralSourceRange(function_literal);
|
||||||
impl()->AddFunctionForNameInference(function_literal);
|
impl()->AddFunctionForNameInference(function_literal);
|
||||||
|
|
||||||
if (V8_UNLIKELY((FLAG_log_function_events))) {
|
if (V8_UNLIKELY((FLAG_log_function_events))) {
|
||||||
|
@ -638,6 +638,9 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
|
|||||||
DCHECK_NULL(target_stack_);
|
DCHECK_NULL(target_stack_);
|
||||||
|
|
||||||
if (has_error()) return nullptr;
|
if (has_error()) return nullptr;
|
||||||
|
|
||||||
|
RecordFunctionLiteralSourceRange(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2450,6 +2453,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
function_literal->set_function_token_position(function_token_pos);
|
function_literal->set_function_token_position(function_token_pos);
|
||||||
function_literal->set_suspend_count(suspend_count);
|
function_literal->set_suspend_count(suspend_count);
|
||||||
|
|
||||||
|
RecordFunctionLiteralSourceRange(function_literal);
|
||||||
|
|
||||||
if (should_post_parallel_task) {
|
if (should_post_parallel_task) {
|
||||||
// Start a parallel parse / compile task on the compiler dispatcher.
|
// Start a parallel parse / compile task on the compiler dispatcher.
|
||||||
info()->parallel_tasks()->Enqueue(info(), function_name, function_literal);
|
info()->parallel_tasks()->Enqueue(info(), function_name, function_literal);
|
||||||
@ -2884,12 +2889,16 @@ FunctionLiteral* Parser::CreateInitializerFunction(
|
|||||||
InitializeClassMembersStatement* stmt =
|
InitializeClassMembersStatement* stmt =
|
||||||
factory()->NewInitializeClassMembersStatement(fields, kNoSourcePosition);
|
factory()->NewInitializeClassMembersStatement(fields, kNoSourcePosition);
|
||||||
statements.Add(stmt);
|
statements.Add(stmt);
|
||||||
return factory()->NewFunctionLiteral(
|
FunctionLiteral* result = factory()->NewFunctionLiteral(
|
||||||
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
|
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
|
||||||
FunctionLiteral::kNoDuplicateParameters,
|
FunctionLiteral::kNoDuplicateParameters,
|
||||||
FunctionLiteral::kAnonymousExpression,
|
FunctionLiteral::kAnonymousExpression,
|
||||||
FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
|
FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
|
||||||
GetNextFunctionLiteralId());
|
GetNextFunctionLiteralId());
|
||||||
|
|
||||||
|
RecordFunctionLiteralSourceRange(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method generates a ClassLiteral AST node.
|
// This method generates a ClassLiteral AST node.
|
||||||
|
@ -933,6 +933,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
|||||||
new (zone()) ConditionalSourceRanges(then_range, else_range));
|
new (zone()) ConditionalSourceRanges(then_range, else_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V8_INLINE void RecordFunctionLiteralSourceRange(FunctionLiteral* node) {
|
||||||
|
if (source_range_map_ == nullptr) return;
|
||||||
|
source_range_map_->Insert(node, new (zone()) FunctionLiteralSourceRanges);
|
||||||
|
}
|
||||||
|
|
||||||
V8_INLINE void RecordBinaryOperationSourceRange(
|
V8_INLINE void RecordBinaryOperationSourceRange(
|
||||||
Expression* node, const SourceRange& right_range) {
|
Expression* node, const SourceRange& right_range) {
|
||||||
if (source_range_map_ == nullptr) return;
|
if (source_range_map_ == nullptr) return;
|
||||||
|
@ -812,22 +812,6 @@ Running test: testPreciseBinaryCoverage
|
|||||||
[0] : {
|
[0] : {
|
||||||
functions : [
|
functions : [
|
||||||
[0] : {
|
[0] : {
|
||||||
functionName : fib
|
|
||||||
isBlockCoverage : true
|
|
||||||
ranges : [
|
|
||||||
[0] : {
|
|
||||||
count : 0
|
|
||||||
endOffset : 73
|
|
||||||
startOffset : 1
|
|
||||||
}
|
|
||||||
[1] : {
|
|
||||||
count : 1
|
|
||||||
endOffset : 72
|
|
||||||
startOffset : 32
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
[1] : {
|
|
||||||
functionName : is_optimized
|
functionName : is_optimized
|
||||||
isBlockCoverage : true
|
isBlockCoverage : true
|
||||||
ranges : [
|
ranges : [
|
||||||
|
@ -22,9 +22,8 @@ f(); f(); %OptimizeFunctionOnNextCall(f); // 0100
|
|||||||
f(); f(); f(); f(); f(); f(); // 0150
|
f(); f(); f(); f(); f(); f(); // 0150
|
||||||
`,
|
`,
|
||||||
[{"start":0,"end":199,"count":1},
|
[{"start":0,"end":199,"count":1},
|
||||||
{"start":0,"end":33,"count":4}, // TODO(jgruber): Invocation count is off.
|
{"start":0,"end":33,"count":16},
|
||||||
{"start":25,"end":31,"count":16},
|
{"start":50,"end":76,"count":8}]
|
||||||
{"start":50,"end":76,"count":2}] // TODO(jgruber): Invocation count is off.
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// This test is tricky: it requires a non-toplevel, optimized function.
|
// This test is tricky: it requires a non-toplevel, optimized function.
|
||||||
@ -44,8 +43,8 @@ TestCoverage("Partial coverage collection",
|
|||||||
f(false); // 0350
|
f(false); // 0350
|
||||||
}(); // 0400
|
}(); // 0400
|
||||||
`,
|
`,
|
||||||
[{"start":52,"end":153,"count":0},
|
[{"start":52,"end":153,"count":1},
|
||||||
{"start":121,"end":137,"count":1}]
|
{"start":111,"end":121,"count":0}]
|
||||||
);
|
);
|
||||||
|
|
||||||
%DebugToggleBlockCoverage(false);
|
%DebugToggleBlockCoverage(false);
|
||||||
|
@ -216,9 +216,8 @@ TestCoverage(
|
|||||||
%PerformMicrotaskCheckpoint(); // 0250
|
%PerformMicrotaskCheckpoint(); // 0250
|
||||||
`,
|
`,
|
||||||
[{"start":0,"end":299,"count":1},
|
[{"start":0,"end":299,"count":1},
|
||||||
{"start":1,"end":201,"count":6}, // TODO(jgruber): Invocation count is off.
|
{"start":1,"end":201,"count":1},
|
||||||
{"start":83,"end":153,"count":4},
|
{"start":83,"end":153,"count":4}]
|
||||||
{"start":153,"end":200,"count":1}]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
@ -415,7 +414,7 @@ TestCoverage(
|
|||||||
{"start":286,"end":350,"count":0},
|
{"start":286,"end":350,"count":0},
|
||||||
{"start":401,"end":701,"count":1},
|
{"start":401,"end":701,"count":1},
|
||||||
{"start":603,"end":700,"count":0},
|
{"start":603,"end":700,"count":0},
|
||||||
{"start":561,"end":568,"count":0}, // TODO(jgruber): Sorting.
|
{"start":561,"end":568,"count":0},
|
||||||
{"start":751,"end":1051,"count":1},
|
{"start":751,"end":1051,"count":1},
|
||||||
{"start":819,"end":820,"count":0},
|
{"start":819,"end":820,"count":0},
|
||||||
{"start":861,"end":1050,"count":0}]
|
{"start":861,"end":1050,"count":0}]
|
||||||
@ -540,10 +539,25 @@ const it = function*() { // 0000
|
|||||||
it.next(); it.next(); // 0250
|
it.next(); it.next(); // 0250
|
||||||
`,
|
`,
|
||||||
[{"start":0,"end":299,"count":1},
|
[{"start":0,"end":299,"count":1},
|
||||||
{"start":11,"end":201,"count":3},
|
{"start":11,"end":201,"count":1},
|
||||||
{"start":64,"end":114,"count":1},
|
{"start":114,"end":121,"count":0},
|
||||||
|
{"start":129,"end":200,"count":0}]
|
||||||
|
);
|
||||||
|
|
||||||
|
TestCoverage(
|
||||||
|
"yield expressions twice",
|
||||||
|
`
|
||||||
|
function* gen() { // 0000
|
||||||
|
yield nop(); // 0050
|
||||||
|
yield nop() ? nop() : nop() // 0100
|
||||||
|
return nop(); // 0150
|
||||||
|
}; // 0200
|
||||||
|
{const it = gen(); it.next(); it.next();} // 0250
|
||||||
|
{const it = gen(); it.next(); it.next();} // 0300
|
||||||
|
`,
|
||||||
|
[{"start":0,"end":349,"count":1},
|
||||||
|
{"start":0,"end":201,"count":2},
|
||||||
{"start":114,"end":121,"count":0},
|
{"start":114,"end":121,"count":0},
|
||||||
{"start":122,"end":129,"count":1},
|
|
||||||
{"start":129,"end":200,"count":0}]
|
{"start":129,"end":200,"count":0}]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -563,9 +577,9 @@ try { // 0200
|
|||||||
`,
|
`,
|
||||||
[{"start":0,"end":499,"count":1},
|
[{"start":0,"end":499,"count":1},
|
||||||
{"start":451,"end":452,"count":0},
|
{"start":451,"end":452,"count":0},
|
||||||
{"start":12,"end":101,"count":3},
|
{"start":12,"end":101,"count":1},
|
||||||
{"start":60,"end":100,"count":0},
|
{"start":60,"end":100,"count":0},
|
||||||
{"start":264,"end":353,"count":3},
|
{"start":264,"end":353,"count":1},
|
||||||
{"start":312,"end":352,"count":0}]
|
{"start":312,"end":352,"count":0}]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -582,9 +596,8 @@ const it = function*() { // 0000
|
|||||||
it.next(); it.return(); // 0450
|
it.next(); it.return(); // 0450
|
||||||
`,
|
`,
|
||||||
[{"start":0,"end":449,"count":1},
|
[{"start":0,"end":449,"count":1},
|
||||||
{"start":11,"end":351,"count":3},
|
{"start":11,"end":351,"count":1},
|
||||||
{"start":112,"end":254,"count":0},
|
{"start":112,"end":254,"count":0},
|
||||||
{"start":254,"end":272,"count":1},
|
|
||||||
{"start":272,"end":350,"count":0}]
|
{"start":272,"end":350,"count":0}]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -601,9 +614,8 @@ const it = function*() { // 0000
|
|||||||
it.next(); it.throw(42); // 0550
|
it.next(); it.throw(42); // 0550
|
||||||
`,
|
`,
|
||||||
[{"start":0,"end":449,"count":1},
|
[{"start":0,"end":449,"count":1},
|
||||||
{"start":11,"end":351,"count":3},
|
{"start":11,"end":351,"count":1},
|
||||||
{"start":112,"end":154,"count":0},
|
{"start":112,"end":154,"count":0},
|
||||||
{"start":154,"end":310,"count":1},
|
|
||||||
{"start":310,"end":350,"count":0}]
|
{"start":310,"end":350,"count":0}]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -619,10 +631,8 @@ it.next(); it.next(); it.next(); // 0250
|
|||||||
it.next(); it.next(); it.next(); // 0300
|
it.next(); it.next(); it.next(); // 0300
|
||||||
`,
|
`,
|
||||||
[{"start":0,"end":349,"count":1},
|
[{"start":0,"end":349,"count":1},
|
||||||
{"start":11,"end":201,"count":7},
|
{"start":11,"end":201,"count":1},
|
||||||
{"start":65,"end":115,"count":1},
|
|
||||||
{"start":115,"end":122,"count":0},
|
{"start":115,"end":122,"count":0},
|
||||||
{"start":123,"end":130,"count":1},
|
|
||||||
{"start":130,"end":200,"count":0}]
|
{"start":130,"end":200,"count":0}]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -642,9 +652,9 @@ try { // 0200
|
|||||||
`,
|
`,
|
||||||
[{"start":0,"end":499,"count":1},
|
[{"start":0,"end":499,"count":1},
|
||||||
{"start":451,"end":452,"count":0},
|
{"start":451,"end":452,"count":0},
|
||||||
{"start":12,"end":101,"count":3},
|
{"start":12,"end":101,"count":1},
|
||||||
{"start":65,"end":100,"count":0},
|
{"start":65,"end":100,"count":0},
|
||||||
{"start":264,"end":353,"count":3},
|
{"start":264,"end":353,"count":1},
|
||||||
{"start":317,"end":352,"count":0}]
|
{"start":317,"end":352,"count":0}]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -659,8 +669,7 @@ f(); // 0200
|
|||||||
%PerformMicrotaskCheckpoint(); // 0250
|
%PerformMicrotaskCheckpoint(); // 0250
|
||||||
`,
|
`,
|
||||||
[{"start":0,"end":299,"count":1},
|
[{"start":0,"end":299,"count":1},
|
||||||
{"start":0,"end":151,"count":3},
|
{"start":0,"end":151,"count":1}]
|
||||||
{"start":61,"end":150,"count":1}]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
@ -676,7 +685,8 @@ b() // 0250
|
|||||||
[{"start":0,"end":299,"count":1},
|
[{"start":0,"end":299,"count":1},
|
||||||
{"start":15,"end":20,"count":0},
|
{"start":15,"end":20,"count":0},
|
||||||
{"start":50,"end":151,"count":2},
|
{"start":50,"end":151,"count":2},
|
||||||
{"start":114,"end":118,"count":0}]);
|
{"start":114,"end":118,"count":0}]
|
||||||
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"LogicalOrExpression IsTest()",
|
"LogicalOrExpression IsTest()",
|
||||||
@ -705,7 +715,8 @@ const c = true && 50 // 0300
|
|||||||
[{"start":0,"end":349,"count":1},
|
[{"start":0,"end":349,"count":1},
|
||||||
{"start":16,"end":21,"count":0},
|
{"start":16,"end":21,"count":0},
|
||||||
{"start":50,"end":151,"count":2},
|
{"start":50,"end":151,"count":2},
|
||||||
{"start":114,"end":118,"count":0}]);
|
{"start":114,"end":118,"count":0}]
|
||||||
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"LogicalAndExpression IsTest()",
|
"LogicalAndExpression IsTest()",
|
||||||
|
@ -10,62 +10,55 @@
|
|||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"class with no fields",
|
"class with no fields",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
}; // 050
|
}; // 050
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":99,"count":1}]
|
||||||
{ start: 0, end: 98, count: 1 },
|
|
||||||
{ start: 0, end: 0, count: 0 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"class that's not created",
|
"class that's not created",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
x = function() { } // 050
|
x = function() { } // 050
|
||||||
}; // 100
|
}; // 100
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":149,"count":1},
|
||||||
{ start: 0, end: 148, count: 1 },
|
{"start":52,"end":70,"count":0}]
|
||||||
{ start: 0, end: 0, count: 0 },
|
|
||||||
{ start: 51, end: 69, count: 0 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"class with field thats not called",
|
"class with field thats not called",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
x = function() { } // 050
|
x = function() { } // 050
|
||||||
}; // 100
|
}; // 100
|
||||||
let x = new X(); // 150
|
let x = new X(); // 150
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":199,"count":1},
|
||||||
{ start: 0, end: 198, count: 1 },
|
{"start":52,"end":70,"count":1},
|
||||||
{ start: 0, end: 0, count: 1 },
|
{"start":56,"end":70,"count":0}]
|
||||||
{ start: 51, end: 69, count: 1 },
|
|
||||||
{ start: 55, end: 69, count: 0 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"class field",
|
"class field",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
x = function() { } // 050
|
x = function() { } // 050
|
||||||
}; // 100
|
}; // 100
|
||||||
let x = new X(); // 150
|
let x = new X(); // 150
|
||||||
x.x(); // 200
|
x.x(); // 200
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":249,"count":1},
|
||||||
{ start: 0, end: 248, count: 1 },
|
{"start":52,"end":70,"count":1},
|
||||||
{ start: 0, end: 0, count: 1 },
|
{"start":56,"end":70,"count":1}]
|
||||||
{ start: 51, end: 69, count: 1 },
|
|
||||||
{ start: 55, end: 69, count: 1 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"non contiguous class field",
|
"non contiguous class field",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
x = function() { } // 050
|
x = function() { } // 050
|
||||||
foo() { } // 100
|
foo() { } // 100
|
||||||
y = function() {} // 150
|
y = function() {} // 150
|
||||||
@ -74,19 +67,17 @@ let x = new X(); // 250
|
|||||||
x.x(); // 300
|
x.x(); // 300
|
||||||
x.y(); // 350
|
x.y(); // 350
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":399,"count":1},
|
||||||
{ start: 0, end: 398, count: 1 },
|
{"start":52,"end":169,"count":1},
|
||||||
{ start: 0, end: 0, count: 1 },
|
{"start":56,"end":70,"count":1},
|
||||||
{ start: 51, end: 168, count: 1 },
|
{"start":102,"end":111,"count":0},
|
||||||
{ start: 55, end: 69, count: 1 },
|
{"start":156,"end":169,"count":1}]
|
||||||
{ start: 101, end: 110, count: 0 },
|
|
||||||
{ start: 155, end: 168, count: 1 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"non contiguous class field thats called",
|
"non contiguous class field thats called",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
x = function() { } // 050
|
x = function() { } // 050
|
||||||
foo() { } // 100
|
foo() { } // 100
|
||||||
y = function() {} // 150
|
y = function() {} // 150
|
||||||
@ -96,29 +87,24 @@ x.x(); // 300
|
|||||||
x.y(); // 350
|
x.y(); // 350
|
||||||
x.foo(); // 400
|
x.foo(); // 400
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":449,"count":1},
|
||||||
{ start: 0, end: 448, count: 1 },
|
{"start":52,"end":169,"count":1},
|
||||||
{ start: 0, end: 0, count: 1 },
|
{"start":56,"end":70,"count":1},
|
||||||
{ start: 51, end: 168, count: 1 },
|
{"start":102,"end":111,"count":1},
|
||||||
{ start: 55, end: 69, count: 1 },
|
{"start":156,"end":169,"count":1}]
|
||||||
{ start: 101, end: 110, count: 1 },
|
|
||||||
{ start: 155, end: 168, count: 1 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"class with initializer iife",
|
"class with initializer iife",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
x = (function() { })() // 050
|
x = (function() { })() // 050
|
||||||
}; // 100
|
}; // 100
|
||||||
let x = new X(); // 150
|
let x = new X(); // 150
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":199,"count":1},
|
||||||
{ start: 0, end: 198, count: 1 },
|
{"start":52,"end":74,"count":1},
|
||||||
{ start: 0, end: 0, count: 1 },
|
{"start":57,"end":71,"count":1}]
|
||||||
{ start: 51, end: 73, count: 1 },
|
|
||||||
{ start: 56, end: 70, count: 1 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
@ -130,56 +116,47 @@ class X { // 050
|
|||||||
}; // 150
|
}; // 150
|
||||||
let x = new X(); // 200
|
let x = new X(); // 200
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":249,"count":1},
|
||||||
{ start: 0, end: 249, count: 1 },
|
{"start":0,"end":15,"count":1},
|
||||||
{ start: 0, end: 15, count: 1 },
|
{"start":102,"end":128,"count":1},
|
||||||
{ start: 50, end: 50, count: 1 },
|
{"start":111,"end":125,"count":1}]
|
||||||
{ start: 102, end: 128, count: 1 },
|
|
||||||
{ start: 111, end: 125, count: 1 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"static class field that's not called",
|
"static class field that's not called",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
static x = function() { } // 050
|
static x = function() { } // 050
|
||||||
}; // 100
|
}; // 100
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":149,"count":1},
|
||||||
{ start: 0, end: 148, count: 1 },
|
{"start":52,"end":77,"count":1},
|
||||||
{ start: 0, end: 0, count: 0 },
|
{"start":63,"end":77,"count":0}]
|
||||||
{ start: 51, end: 76, count: 1 },
|
|
||||||
{ start: 62, end: 76, count: 0 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"static class field",
|
"static class field",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
static x = function() { } // 050
|
static x = function() { } // 050
|
||||||
}; // 100
|
}; // 100
|
||||||
X.x(); // 150
|
X.x(); // 150
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":199,"count":1},
|
||||||
{ start: 0, end: 198, count: 1 },
|
{"start":52,"end":77,"count":1},
|
||||||
{ start: 0, end: 0, count: 0 },
|
{"start":63,"end":77,"count":1}]
|
||||||
{ start: 51, end: 76, count: 1 },
|
|
||||||
{ start: 62, end: 76, count: 1 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
"static class field with iife",
|
"static class field with iife",
|
||||||
`class X { // 000
|
`
|
||||||
|
class X { // 000
|
||||||
static x = (function() { })() // 050
|
static x = (function() { })() // 050
|
||||||
}; // 100
|
}; // 100
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":149,"count":1},
|
||||||
{ start: 0, end: 148, count: 1 },
|
{"start":52,"end":81,"count":1},
|
||||||
{ start: 0, end: 0, count: 0 },
|
{"start":64,"end":78,"count":1}]
|
||||||
{ start: 51, end: 80, count: 1 },
|
|
||||||
{ start: 63, end: 77, count: 1 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TestCoverage(
|
TestCoverage(
|
||||||
@ -190,11 +167,8 @@ class X { // 050
|
|||||||
static [f()] = (function() { })() // 100
|
static [f()] = (function() { })() // 100
|
||||||
}; // 150
|
}; // 150
|
||||||
`,
|
`,
|
||||||
[
|
[{"start":0,"end":199,"count":1},
|
||||||
{ start: 0, end: 199, count: 1 },
|
{"start":0,"end":15,"count":1},
|
||||||
{ start: 0, end: 15, count: 1 },
|
{"start":102,"end":135,"count":1},
|
||||||
{ start: 50, end: 50, count: 0 },
|
{"start":118,"end":132,"count":1}]
|
||||||
{ start: 102, end: 135, count: 1 },
|
|
||||||
{ start: 118, end: 132, count: 1 }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user