b42415402f
This CL implements general infrastructure for block coverage together with initial support for if-statements. Coverage output can be generated in lcov format by d8 as follows: $ d8 --block-coverage --lcov=$(echo ~/simple-if.lcov) ~/simple-if.js $ genhtml ~/simple-if.lcov -o ~/simple-if $ chrome ~/simple-if/index.html A high level overview of the implementation follows: The parser now collects source ranges unconditionally for relevant AST nodes. Memory overhead is very low and this seemed like the cleanest and simplest alternative. Bytecode generation uses these ranges to allocate coverage slots and insert IncBlockCounter instructions (e.g. at the beginning of then- and else blocks for if-statements). The slot-range mapping is generated here and passed on through CompilationInfo, and is later accessible through the SharedFunctionInfo. The IncBlockCounter bytecode fetches the slot-range mapping (called CoverageInfo) from the shared function info and simply increments the counter. We don't collect native-context-specific counts as they are irrelevant to our use-cases. Coverage information is finally generated on-demand through Coverage::Collect. The only current consumer is a d8 front-end with lcov-style output, but the short-term goal is to expose this through the inspector protocol. BUG=v8:6000 CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_chromium_rel_ng Review-Url: https://codereview.chromium.org/2882973002 Cr-Commit-Position: refs/heads/master@{#45737}
84 lines
1.9 KiB
JavaScript
84 lines
1.9 KiB
JavaScript
// Copyright 2017 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.
|
|
|
|
// Flags: --allow-natives-syntax --no-always-opt --block-coverage
|
|
|
|
// Test precise code coverage.
|
|
|
|
function GetCoverage(source) {
|
|
for (var script of %DebugCollectCoverage()) {
|
|
if (script.script.source == source) return script;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function TestCoverage(name, source, expectation) {
|
|
source = source.trim();
|
|
eval(source);
|
|
%CollectGarbage("collect dead objects");
|
|
var coverage = GetCoverage(source);
|
|
var result = JSON.stringify(coverage);
|
|
print(result);
|
|
assertEquals(JSON.stringify(expectation), result, name + " failed");
|
|
}
|
|
|
|
%DebugToggleBlockCoverage(true);
|
|
|
|
TestCoverage(
|
|
"call an IIFE",
|
|
`
|
|
(function f() {})();
|
|
`,
|
|
[{"start":0,"end":20,"count":1},{"start":1,"end":16,"count":1}]
|
|
);
|
|
|
|
TestCoverage(
|
|
"call locally allocated function",
|
|
`
|
|
for (var i = 0; i < 10; i++) {
|
|
let f = () => 1;
|
|
i += f();
|
|
}
|
|
`,
|
|
[{"start":0,"end":63,"count":1},{"start":41,"end":48,"count":5}]
|
|
);
|
|
|
|
TestCoverage(
|
|
"if statements",
|
|
`
|
|
function g() {}
|
|
function f(x) {
|
|
if (x == 42) {
|
|
if (x == 43) g(); else g();
|
|
}
|
|
if (x == 42) { g(); } else { g(); }
|
|
if (x == 42) g(); else g();
|
|
if (false) g(); else g();
|
|
if (false) g();
|
|
if (true) g(); else g();
|
|
if (true) g();
|
|
}
|
|
f(42);
|
|
f(43);
|
|
`,
|
|
[{"start":0,"end":258,"count":1},
|
|
{"start":0,"end":15,"count":11},
|
|
{"start":16,"end":244,"count":2},
|
|
{"start":45,"end":83,"count":1},
|
|
{"start":64,"end":69,"count":0},
|
|
{"start":71,"end":79,"count":1},
|
|
{"start":98,"end":107,"count":1},
|
|
{"start":109,"end":121,"count":1},
|
|
{"start":136,"end":141,"count":1},
|
|
{"start":143,"end":151,"count":1},
|
|
{"start":164,"end":169,"count":0},
|
|
{"start":171,"end":179,"count":2},
|
|
{"start":192,"end":197,"count":0},
|
|
{"start":209,"end":214,"count":2},
|
|
{"start":216,"end":224,"count":0},
|
|
{"start":236,"end":241,"count":2}]
|
|
);
|
|
|
|
%DebugToggleBlockCoverage(false);
|