v8/test/mjsunit/code-coverage-block.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1236 lines
43 KiB
JavaScript
Raw Normal View History

[coverage] Block coverage with support for IfStatements 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}
2017-06-06 15:44:55 +00:00
// 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 --no-stress-flush-bytecode
// Files: test/mjsunit/code-coverage-utils.js
[coverage] Block coverage with support for IfStatements 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}
2017-06-06 15:44:55 +00:00
%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",
`let f = () => 1; f();`,
[{"start":0,"end":21,"count":1},{"start":8,"end":15,"count":1}]
[coverage] Block coverage with support for IfStatements 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}
2017-06-06 15:44:55 +00:00
);
TestCoverage(
"if statements",
`
function g() {} // 0000
function f(x) { // 0050
if (x == 42) { // 0100
if (x == 43) g(); else g(); // 0150
} // 0200
if (x == 42) { g(); } else { g(); } // 0250
if (x == 42) g(); else g(); // 0300
if (false) g(); else g(); // 0350
if (false) g(); // 0400
if (true) g(); else g(); // 0450
if (true) g(); // 0500
} // 0550
f(42); // 0600
f(43); // 0650
if (true) { // 0700
const foo = 'bar'; // 0750
} else { // 0800
const bar = 'foo'; // 0850
} // 0900
[coverage] Block coverage with support for IfStatements 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}
2017-06-06 15:44:55 +00:00
`,
[{"start":0,"end":949,"count":1},
{"start":801,"end":901,"count":0},
[coverage] Block coverage with support for IfStatements 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}
2017-06-06 15:44:55 +00:00
{"start":0,"end":15,"count":11},
{"start":50,"end":551,"count":2},
{"start":115,"end":203,"count":1},
{"start":167,"end":171,"count":0},
{"start":265,"end":287,"count":1},
{"start":315,"end":329,"count":1},
{"start":363,"end":367,"count":0},
{"start":413,"end":417,"count":0},
{"start":466,"end":476,"count":0}]
);
TestCoverage(
"if statement (early return)",
`
!function() { // 0000
if (true) { // 0050
nop(); // 0100
return; // 0150
nop(); // 0200
} // 0250
nop(); // 0300
}() // 0350
`,
[{"start":0,"end":399,"count":1},
{"start":1,"end":351,"count":1},
{"start":161,"end":350,"count":0}]
[coverage] Block coverage with support for IfStatements 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}
2017-06-06 15:44:55 +00:00
);
TestCoverage(
"if statement (no semi-colon)",
`
!function() { // 0000
if (true) nop() // 0050
if (true) nop(); else nop() // 0100
nop(); // 0150
}() // 0200
`,
[{"start":0,"end":249,"count":1},
{"start":1,"end":201,"count":1},
{"start":118,"end":129,"count":0}]
);
TestCoverage(
"for statements",
`
function g() {} // 0000
!function() { // 0050
for (var i = 0; i < 12; i++) g(); // 0100
for (var i = 0; i < 12; i++) { // 0150
g(); // 0200
} // 0250
for (var i = 0; false; i++) g(); // 0300
for (var i = 0; true; i++) break; // 0350
for (var i = 0; i < 12; i++) { // 0400
if (i % 3 == 0) g(); else g(); // 0450
} // 0500
}(); // 0550
`,
[{"start":0,"end":599,"count":1},
{"start":0,"end":15,"count":36},
{"start":51,"end":551,"count":1},
{"start":131,"end":135,"count":12},
{"start":181,"end":253,"count":12},
{"start":330,"end":334,"count":0},
{"start":431,"end":503,"count":12},
{"start":470,"end":474,"count":4},
{"start":474,"end":484,"count":8}]
);
TestCoverage(
"for statements pt. 2",
`
function g() {} // 0000
!function() { // 0050
let j = 0; // 0100
for (let i = 0; i < 12; i++) g(); // 0150
for (const i = 0; j < 12; j++) g(); // 0200
for (j = 0; j < 12; j++) g(); // 0250
for (;;) break; // 0300
}(); // 0350
`,
[{"start":0,"end":399,"count":1},
{"start":0,"end":15,"count":36},
{"start":51,"end":351,"count":1},
{"start":181,"end":185,"count":12},
{"start":233,"end":237,"count":12},
{"start":277,"end":281,"count":12}]
);
TestCoverage(
"for statements (no semicolon)",
`
function g() {} // 0000
!function() { // 0050
for (let i = 0; i < 12; i++) g() // 0100
for (let i = 0; i < 12; i++) break // 0150
for (let i = 0; i < 12; i++) break; g() // 0200
}(); // 0250
`,
[{"start":0,"end":299,"count":1},
{"start":0,"end":15,"count":13},
{"start":51,"end":251,"count":1},
{"start":131,"end":134,"count":12}]
);
TestCoverage(
"for statement (early return)",
`
!function() { // 0000
for (var i = 0; i < 10; i++) { // 0050
nop(); // 0100
continue; // 0150
nop(); // 0200
} // 0250
nop(); // 0300
for (;;) { // 0350
nop(); // 0400
break; // 0450
nop(); // 0500
} // 0550
nop(); // 0600
for (;;) { // 0650
nop(); // 0700
return; // 0750
nop(); // 0800
} // 0850
nop(); // 0900
}() // 0950
`,
[{"start":0,"end":999,"count":1},
{"start":1,"end":951,"count":1},
{"start":81,"end":253,"count":10},
{"start":163,"end":253,"count":0},
{"start":460,"end":553,"count":0},
{"start":761,"end":950,"count":0}]
);
TestCoverage(
"for-of and for-in statements",
`
!function() { // 0000
var i; // 0050
for (i of [0,1,2,3]) { nop(); } // 0100
for (let j of [0,1,2,3]) { nop(); } // 0150
for (i in [0,1,2,3]) { nop(); } // 0200
for (let j in [0,1,2,3]) { nop(); } // 0250
var xs = [{a:0, b:1}, {a:1,b:0}]; // 0300
for (var {a: x, b: y} of xs) { nop(); } // 0350
}(); // 0400
`,
[{"start":0,"end":449,"count":1},
{"start":1,"end":401,"count":1},
{"start":123,"end":133,"count":4},
{"start":177,"end":187,"count":4},
{"start":223,"end":233,"count":4},
{"start":277,"end":287,"count":4},
{"start":381,"end":391,"count":2}]
);
TestCoverage(
"while and do-while statements",
`
function g() {} // 0000
!function() { // 0050
var i; // 0100
i = 0; while (i < 12) i++; // 0150
i = 0; while (i < 12) { g(); i++; } // 0200
i = 0; while (false) g(); // 0250
i = 0; while (true) break; // 0300
// 0350
i = 0; do i++; while (i < 12); // 0400
i = 0; do { g(); i++; } // 0450
while (i < 12); // 0500
i = 0; do { g(); } while (false); // 0550
i = 0; do { break; } while (true); // 0600
}(); // 0650
`,
[{"start":0,"end":699,"count":1},
{"start":0,"end":15,"count":25},
{"start":51,"end":651,"count":1},
{"start":174,"end":178,"count":12},
{"start":224,"end":237,"count":12},
{"start":273,"end":277,"count":0},
{"start":412,"end":416,"count":12},
{"start":462,"end":475,"count":12}]
);
TestCoverage(
"while statement (early return)",
`
!function() { // 0000
let i = 0; // 0050
while (i < 10) { // 0100
i++; // 0150
continue; // 0200
nop(); // 0250
} // 0300
nop(); // 0350
while (true) { // 0400
nop(); // 0450
break; // 0500
nop(); // 0550
} // 0600
nop(); // 0650
while (true) { // 0700
nop(); // 0750
return; // 0800
nop(); // 0850
} // 0900
nop(); // 0950
}() // 1000
`,
[{"start":0,"end":1049,"count":1},
{"start":1,"end":1001,"count":1},
{"start":117,"end":303,"count":10},
{"start":213,"end":303,"count":0},
{"start":510,"end":603,"count":0},
{"start":811,"end":1000,"count":0}]
);
TestCoverage(
"do-while statement (early return)",
`
!function() { // 0000
let i = 0; // 0050
do { // 0100
i++; // 0150
continue; // 0200
nop(); // 0250
} while (i < 10); // 0300
nop(); // 0350
do { // 0400
nop(); // 0450
break; // 0500
nop(); // 0550
} while (true); // 0600
nop(); // 0650
do { // 0700
nop(); // 0750
return; // 0800
nop(); // 0850
} while (true); // 0900
nop(); // 0950
}() // 1000
`,
[{"start":0,"end":1049,"count":1},
{"start":1,"end":1001,"count":1},
{"start":105,"end":303,"count":10},
{"start":213,"end":303,"count":0},
{"start":510,"end":603,"count":0},
{"start":811,"end":1000,"count":0}]
);
TestCoverage(
"return statements",
`
!function() { nop(); return; nop(); }(); // 0000
!function() { nop(); return 42; // 0050
nop(); }(); // 0100
`,
[{"start":0,"end":149,"count":1},
{"start":1,"end":37,"count":1},
{"start":28,"end":36,"count":0},
{"start":51,"end":122,"count":1},
{"start":81,"end":121,"count":0}]
);
TestCoverage(
"try/catch/finally statements",
`
!function() { // 0000
try { nop(); } catch (e) { nop(); } // 0050
try { nop(); } finally { nop(); } // 0100
try { // 0150
try { throw 42; } catch (e) { nop(); }// 0200
} catch (e) { nop(); } // 0250
try { // 0300
try { throw 42; } finally { nop(); } // 0350
} catch (e) { nop(); } // 0400
try { // 0450
throw 42; // 0500
} catch (e) { // 0550
nop(); // 0600
} finally { // 0650
nop(); // 0700
} // 0750
}(); // 0800
`,
[{"start":0,"end":849,"count":1},
{"start":1,"end":801,"count":1},
{"start":67,"end":87,"count":0},
{"start":254,"end":274,"count":0}]
);
TestCoverage("try/catch/finally statements with early return",
`
!function() { // 0000
try { throw 42; } catch (e) { return; } // 0050
nop(); // 0100
}(); // 0150
!function() { // 0200
try { throw 42; } catch (e) {} // 0250
finally { return; } // 0300
nop(); // 0350
}(); // 0400
`,
[{"start":0,"end":449,"count":1},
{"start":1,"end":151,"count":1},
{"start":91,"end":150,"count":0},
{"start":201,"end":401,"count":1},
{"start":321,"end":400,"count":0}]
);
TestCoverage(
"early return in blocks",
`
!function() { // 0000
try { throw 42; } catch (e) { return; } // 0050
nop(); // 0100
}(); // 0150
!function() { // 0200
try { nop(); } finally { return; } // 0250
nop(); // 0300
}(); // 0350
!function() { // 0400
{ // 0450
let x = 42; // 0500
return () => x; // 0550
} // 0600
nop(); // 0650
}(); // 0700
!function() { // 0750
try { throw 42; } catch (e) { // 0800
return; // 0850
nop(); // 0900
} // 0950
nop(); // 1000
}(); // 1050
`,
[{"start":0,"end":1099,"count":1},
{"start":1,"end":151,"count":1},
{"start":91,"end":150,"count":0},
{"start":201,"end":351,"count":1},
{"start":286,"end":350,"count":0},
{"start":401,"end":701,"count":1},
{"start":603,"end":700,"count":0},
{"start":561,"end":568,"count":0},
{"start":751,"end":1051,"count":1},
{"start":861,"end":1050,"count":0}]
);
TestCoverage(
"switch statements",
`
!function() { // 0000
var x = 42; // 0050
switch (x) { // 0100
case 41: nop(); break; // 0150
case 42: nop(); break; // 0200
default: nop(); break; // 0250
} // 0300
}(); // 0350
`,
[{"start":0,"end":399,"count":1},
{"start":1,"end":351,"count":1},
{"start":154,"end":176,"count":0},
{"start":254,"end":276,"count":0}]
);
TestCoverage(
"labeled break statements",
`
!function() { // 0000
var x = 42; // 0050
l0: switch (x) { // 0100
case 41: return; // 0150
case 42: // 0200
switch (x) { case 42: break l0; } // 0250
break; // 0300
} // 0350
l1: for (;;) { // 0400
for (;;) break l1; // 0450
} // 0500
l2: while (true) { // 0550
while (true) break l2; // 0600
} // 0650
l3: do { // 0700
do { break l3; } while (true); // 0750
} while (true); // 0800
l4: { break l4; } // 0850
l5: for (;;) for (;;) break l5; // 0900
}(); // 0950
`,
[{"start":0,"end":999,"count":1},
{"start":1,"end":951,"count":1},
{"start":152,"end":168,"count":0},
{"start":287,"end":310,"count":0}]
);
TestCoverage(
"labeled continue statements",
`
!function() { // 0000
l0: for (var i0 = 0; i0 < 2; i0++) { // 0050
for (;;) continue l0; // 0100
} // 0150
var i1 = 0; // 0200
l1: while (i1 < 2) { // 0250
i1++; // 0300
while (true) continue l1; // 0350
} // 0400
var i2 = 0; // 0450
l2: do { // 0500
i2++; // 0550
do { continue l2; } while (true); // 0600
} while (i2 < 2); // 0650
}(); // 0700
`,
[{"start":0,"end":749,"count":1},
{"start":1,"end":701,"count":1},
{"start":87,"end":153,"count":2},
{"start":271,"end":403,"count":2},
{"start":509,"end":653,"count":2}]
);
TestCoverage(
"conditional expressions",
`
var TRUE = true; // 0000
var FALSE = false; // 0050
!function() { // 0100
TRUE ? nop() : nop(); // 0150
true ? nop() : nop(); // 0200
false ? nop() : nop(); // 0250
FALSE ? TRUE ? nop() // 0300
: nop() // 0350
: nop(); // 0400
TRUE ? FALSE ? nop() // 0450
: nop() // 0500
: nop(); // 0550
TRUE ? nop() : FALSE ? nop() // 0600
: nop(); // 0650
FALSE ? nop() : TRUE ? nop() // 0700
: nop(); // 0750
}(); // 0800
`,
[{"start":0,"end":849,"count":1},
{"start":101,"end":801,"count":1},
{"start":165,"end":172,"count":0},
{"start":215,"end":222,"count":0},
{"start":258,"end":265,"count":0},
{"start":308,"end":372,"count":0},
{"start":465,"end":472,"count":0},
{"start":557,"end":564,"count":0},
{"start":615,"end":680,"count":0},
{"start":708,"end":715,"count":0},
{"start":773,"end":780,"count":0}]
);
TestCoverage(
"yield expressions",
`
const it = function*() { // 0000
yield nop(); // 0050
yield nop() ? nop() : nop() // 0100
return nop(); // 0150
}(); // 0200
it.next(); it.next(); // 0250
`,
[{"start":0,"end":299,"count":1},
{"start":11,"end":201,"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":129,"end":200,"count":0}]
);
TestCoverage(
"yield expressions (.return and .throw)",
`
const it0 = function*() { // 0000
yield 1; yield 2; yield 3; // 0050
}(); // 0100
it0.next(); it0.return(); // 0150
try { // 0200
const it1 = function*() { // 0250
yield 1; yield 2; yield 3; // 0300
}(); // 0350
it1.next(); it1.throw(); // 0400
} catch (e) {} // 0450
`,
[{"start":0,"end":499,"count":1},
{"start":12,"end":101,"count":1},
{"start":60,"end":100,"count":0},
{"start":264,"end":353,"count":1},
{"start":312,"end":352,"count":0}]
);
TestCoverage("yield expressions (.return and try/catch/finally)",
`
const it = function*() { // 0000
try { // 0050
yield 1; yield 2; yield 3; // 0100
} catch (e) { // 0150
nop(); // 0200
} finally { nop(); } // 0250
yield 4; // 0300
}(); // 0350
it.next(); it.return(); // 0450
`,
[{"start":0,"end":449,"count":1},
{"start":11,"end":351,"count":1},
{"start":112,"end":254,"count":0},
{"start":272,"end":350,"count":0}]
);
TestCoverage("yield expressions (.throw and try/catch/finally)",
`
const it = function*() { // 0000
try { // 0050
yield 1; yield 2; yield 3; // 0100
} catch (e) { // 0150
nop(); // 0200
} finally { nop(); } // 0250
yield 4; // 0300
}(); // 0350
it.next(); it.throw(42); // 0550
`,
[{"start":0,"end":449,"count":1},
{"start":11,"end":351,"count":1},
{"start":112,"end":154,"count":0},
{"start":310,"end":350,"count":0}]
);
TestCoverage(
"yield* expressions",
`
const it = function*() { // 0000
yield* gen(); // 0050
yield* nop() ? gen() : gen() // 0100
return gen(); // 0150
}(); // 0200
it.next(); it.next(); it.next(); // 0250
it.next(); it.next(); it.next(); // 0300
`,
[{"start":0,"end":349,"count":1},
{"start":11,"end":201,"count":1},
{"start":115,"end":122,"count":0},
{"start":130,"end":200,"count":0}]
);
TestCoverage(
"yield* expressions (.return and .throw)",
`
const it0 = function*() { // 0000
yield* gen(); yield* gen(); yield 3; // 0050
}(); // 0100
it0.next(); it0.return(); // 0150
try { // 0200
const it1 = function*() { // 0250
yield* gen(); yield* gen(); yield 3; // 0300
}(); // 0350
it1.next(); it1.throw(); // 0400
} catch (e) {} // 0450
`,
[{"start":0,"end":499,"count":1},
{"start":12,"end":101,"count":1},
{"start":65,"end":100,"count":0},
{"start":264,"end":353,"count":1},
{"start":317,"end":352,"count":0}]
);
TestCoverage(
"LogicalOrExpression assignment",
`
const a = true || 99 // 0000
function b () { // 0050
const b = a || 2 // 0100
} // 0150
b() // 0200
b() // 0250
`,
[{"start":0,"end":299,"count":1},
{"start":15,"end":20,"count":0},
{"start":50,"end":151,"count":2},
{"start":114,"end":118,"count":0}]
);
TestCoverage(
"LogicalOrExpression IsTest()",
`
true || false // 0000
const a = 99 // 0050
a || 50 // 0100
const b = false // 0150
if (b || true) {} // 0200
`,
[{"start":0,"end":249,"count":1},
{"start":5,"end":13,"count":0},
{"start":102,"end":107,"count":0}]);
TestCoverage(
"LogicalAndExpression assignment",
`
const a = false && 99 // 0000
function b () { // 0050
const b = a && 2 // 0100
} // 0150
b() // 0200
b() // 0250
const c = true && 50 // 0300
`,
[{"start":0,"end":349,"count":1},
{"start":16,"end":21,"count":0},
{"start":50,"end":151,"count":2},
{"start":114,"end":118,"count":0}]
);
TestCoverage(
"LogicalAndExpression IsTest()",
`
false && true // 0000
const a = 0 // 0050
a && 50 // 0100
const b = true // 0150
if (b && true) {} // 0200
true && true // 0250
`,
[{"start":0,"end":299,"count":1},
{"start":6,"end":13,"count":0},
{"start":102,"end":107,"count":0}]);
TestCoverage(
"NaryLogicalOr assignment",
`
const a = true // 0000
const b = false // 0050
const c = false || false || 99 // 0100
const d = false || true || 99 // 0150
const e = true || true || 99 // 0200
const f = b || b || 99 // 0250
const g = b || a || 99 // 0300
const h = a || a || 99 // 0350
const i = a || (b || c) || d // 0400
`,
[{"start":0,"end":449,"count":1},
{"start":174,"end":179,"count":0},
{"start":215,"end":222,"count":0},
{"start":223,"end":228,"count":0},
{"start":317,"end":322,"count":0},
{"start":362,"end":366,"count":0},
{"start":367,"end":372,"count":0},
{"start":412,"end":423,"count":0},
{"start":424,"end":428,"count":0}]);
TestCoverage(
"NaryLogicalOr IsTest()",
`
const a = true // 0000
const b = false // 0050
false || false || 99 // 0100
false || true || 99 // 0150
true || true || 99 // 0200
b || b || 99 // 0250
b || a || 99 // 0300
a || a || 99 // 0350
`,
[{"start":0,"end":399,"count":1},
{"start":164,"end":169,"count":0},
{"start":205,"end":212,"count":0},
{"start":213,"end":218,"count":0},
{"start":307,"end":312,"count":0},
{"start":352,"end":356,"count":0},
{"start":357,"end":362,"count":0}]);
TestCoverage(
"NaryLogicalAnd assignment",
`
const a = true // 0000
const b = false // 0050
const c = false && false && 99 // 0100
const d = false && true && 99 // 0150
const e = true && true && 99 // 0200
const f = true && false || true // 0250
const g = true || false && true // 0300
`,
[{"start":0,"end":349,"count":1},
{"start":116,"end":124,"count":0},
{"start":125,"end":130,"count":0},
{"start":166,"end":173,"count":0},
{"start":174,"end":179,"count":0},
{"start":315,"end":331,"count":0}
]);
TestCoverage(
"NaryLogicalAnd IsTest()",
`
const a = true // 0000
const b = false // 0050
false && false && 99 // 0100
false && true && 99 // 0150
true && true && 99 // 0200
true && false || true // 0250
true || false && true // 0300
false || false || 99 || 55 // 0350
`,
[{"start":0,"end":399,"count":1},
{"start":106,"end":114,"count":0},
{"start":115,"end":120,"count":0},
{"start":156,"end":163,"count":0},
{"start":164,"end":169,"count":0},
{"start":305,"end":321,"count":0},
{"start":371,"end":376,"count":0}]);
// see regression: https://bugs.chromium.org/p/chromium/issues/detail?id=785778
TestCoverage(
"logical expressions + conditional expressions",
`
const a = true // 0000
const b = 99 // 0050
const c = false // 0100
const d = '' // 0150
const e = a && (b ? 'left' : 'right') // 0200
const f = a || (b ? 'left' : 'right') // 0250
const g = c || d ? 'left' : 'right' // 0300
const h = a && b && (b ? 'left' : 'right')// 0350
const i = d || c || (c ? 'left' : 'right')// 0400
`,
[{"start":0,"end":449,"count":1},
{"start":227,"end":236,"count":0},
{"start":262,"end":287,"count":0},
{"start":317,"end":325,"count":0},
{"start":382,"end":391,"count":0},
{"start":423,"end":431,"count":0}
]);
TestCoverage(
"https://crbug.com/827530",
`
Util = {}; // 0000
Util.escape = function UtilEscape(str) { // 0050
if (!str) { // 0100
return 'if'; // 0150
} else { // 0200
return 'else'; // 0250
} // 0300
}; // 0350
Util.escape("foo.bar"); // 0400
`,
[{"start":0,"end":449,"count":1},
{"start":64,"end":351,"count":1},
{"start":112,"end":203,"count":0}]
2018-10-10 12:44:11 +00:00
);
TestCoverage(
"https://crbug.com/v8/8237",
`
!function() { // 0000
if (true) // 0050
while (false) return; else nop(); // 0100
}(); // 0150
!function() { // 0200
if (true) l0: { break l0; } else // 0250
if (nop()) { } // 0300
}(); // 0350
!function() { // 0400
if (true) { if (false) { return; } // 0450
} else if (nop()) { } }(); // 0500
!function(){ // 0550
if(true)while(false)return;else nop() // 0600
}(); // 0650
!function(){ // 0700
if(true) l0:{break l0}else if (nop()){} // 0750
}(); // 0800
!function(){ // 0850
if(true){if(false){return}}else // 0900
if(nop()){} // 0950
}(); // 1000
`,
[{"start":0,"end":1049,"count":1},
{"start":1,"end":151,"count":1},
{"start":118,"end":137,"count":0},
{"start":201,"end":351,"count":1},
{"start":279,"end":318,"count":0},
2018-10-10 12:44:11 +00:00
{"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":774,"end":791,"count":0},
2018-10-10 12:44:11 +00:00
{"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}]
);
TestCoverage(
"https://crbug.com/927464",
`
!function f() { // 0000
function unused() { nop(); } // 0050
nop(); // 0100
}(); // 0150
`,
[{"start":0,"end":199,"count":1},
{"start":1,"end":151,"count":1},
{"start":52,"end":80,"count":0}]
);
TestCoverage(
"https://crbug.com/v8/8691",
`
function f(shouldThrow) { // 0000
if (shouldThrow) { // 0050
throw Error('threw') // 0100
} // 0150
} // 0200
try { // 0250
f(true) // 0300
} catch (err) { // 0350
// 0400
} // 0450
try { // 0500
f(false) // 0550
} catch (err) {} // 0600
`,
[{"start":0,"end":649,"count":1},
{"start":602,"end":616,"count":0},
{"start":0,"end":201,"count":2},
{"start":69,"end":153,"count":1}]
);
TestCoverage(
"https://crbug.com/v8/9705",
`
function f(x) { // 0000
switch (x) { // 0050
case 40: nop(); // 0100
case 41: nop(); return 1; // 0150
case 42: nop(); break; // 0200
} // 0250
return 3; // 0300
}; // 0350
f(40); // 0400
f(41); // 0450
f(42); // 0500
f(43); // 0550
`,
[{"start":0,"end":599,"count":1},
{"start":0,"end":351,"count":4},
{"start":104,"end":119,"count":1},
{"start":154,"end":179,"count":2},
{"start":204,"end":226,"count":1},
{"start":253,"end":350,"count":2}]
);
TestCoverage(
"https://crbug.com/v8/9705",
`
function f(x) { // 0000
switch (x) { // 0050
case 40: nop(); // 0100
case 41: nop(); return 1; // 0150
case 42: nop(); break; // 0200
} // 0250
return 3; // 0300
}; // 0350
f(42); // 0400
f(43); // 0450
`,
[{"start":0,"end":499,"count":1},
{"start":0,"end":351,"count":2},
{"start":104,"end":119,"count":0},
{"start":154,"end":179,"count":0},
{"start":204,"end":226,"count":1}]
);
[coverage] Correctly report coverage for inline scripts This fixes a bug where coverage for the inline script <script>function foo() {}<script> started to get deterministically reported as covered after crrev.com/c/1771776, while before it, we most of the time reported it as uncovered (depending on heap order of SFIs). The correct result is to report `foo` as uncovered as it is never called. The problem arose from the fact that v8:9212 needed to handle extra-wrappers around scripts correctly. Those wrappers have the same source range as the wrapped script and a call count of zero even if the wrapped script is executed. To filter them out, we previously determined nesting for identical source ranges by ascending call count. However, in the script case above, the script has call count one, while `foo` (which has the same source range) has call count zero. In this case, nesting is decreasing order of call counts. This CL is a minimal change that sorts SFIs which are top-level to the front, only then considers call counts in descending order. This preserves the behavior that node's extra wrappers are sorted to the front (and then filtered out by existing logic), but also ensures that for the example above, we report the script's coverage before the coverage for `foo`. Bug: v8:9857, v9:9212 Change-Id: Id224b0d8f12028b1f586ee5039e126bb5b8d8d36 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1863197 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#64307}
2019-10-16 07:18:23 +00:00
TestCoverage(
"https://crbug.com/v8/9857",
`function foo() {}`,
[{"start":0,"end":17,"count":1},
{"start":0,"end":17,"count":0}]
);
TestCoverage(
"https://crbug.com/v8/9857",
`function foo() {function bar() {}}; foo()`,
[{"start":0,"end":41,"count":1},
{"start":0,"end":34,"count":1},
{"start":16,"end":33,"count":0}]
);
TestCoverage(
"https://crbug.com/v8/9952",
`
function test(foo = "foodef") { // 0000
return {bar}; // 0050
// 0100
function bar() { // 0150
console.log("test"); // 0200
} // 0250
} // 0300
test().bar(); // 0350
`,
[{"start":0,"end":399,"count":1},
{"start":0,"end":301,"count":1},
{"start":152,"end":253,"count":1}]);
TestCoverage(
"https://crbug.com/v8/9952",
`
function test(foo = (()=>{})) { // 0000
return {foo}; // 0050
} // 0100
// 0150
test(()=>{}).foo(); // 0200
`,
[{"start":0,"end":249,"count":1},
{"start":0,"end":101,"count":1},
{"start":21,"end":27,"count":0},
{"start":205,"end":211,"count":1}]
);
TestCoverage(
"https://crbug.com/v8/10030 - original",
`
function a (shouldThrow) { // 0000
try { // 0050
if (shouldThrow) // 0100
throw Error('I threw!'); // 0150
return 'I ran'; // 0200
} catch(e) { // 0250
console.info('caught'); // 0300
} // 0350
} // 0400
a(false); // 0450
a(true); // 0500
`,
[{"start":0,"end":549,"count":1},
{"start":0,"end":401,"count":2},
{"start":156,"end":353,"count":1}]
);
TestCoverage(
"https://crbug.com/v8/10030 - only throw",
`
function a (shouldThrow) { // 0000
try { // 0050
if (shouldThrow) // 0100
throw Error('I threw!'); // 0150
return 'I ran'; // 0200
} catch(e) { // 0250
console.info('caught'); // 0300
} // 0350
} // 0400
a(true); // 0450
`,
[{"start":0,"end":499,"count":1},
{"start":0,"end":401,"count":1},
{"start":180,"end":254,"count":0}]
);
TestCoverage(
"https://crbug.com/v8/10030 - finally",
`
function a (shouldThrow) { // 0000
try { // 0050
return 'I ran'; // 0100
} finally { // 0150
console.info('finally'); // 0200
} // 0250
} // 0300
a(false); // 0350
a(true); // 0400
`,
[{"start":0,"end":449,"count":1},
{"start":0,"end":301,"count":2}]);
TestCoverage(
"https://crbug.com/v8/10030 - catch & finally",
`
function a (shouldThrow) { // 0000
try { // 0050
return 'I ran'; // 0100
} catch (e) { // 0150
console.info('caught'); // 0200
} finally { // 0250
console.info('finally'); // 0300
} // 0350
} // 0400
a(false); // 0450
a(true); // 0500
`,
[{"start":0,"end":549,"count":1},
{"start":0,"end":401,"count":2},
{"start":154,"end":254,"count":0}]);
TestCoverage(
"https://crbug.com/v8/11231 - nullish coalescing",
`
const a = true // 0000
const b = false // 0050
const c = undefined // 0100
const d = a ?? 99 // 0150
const e = 33 // 0200
const f = b ?? (c ?? 99) // 0250
const g = 33 // 0300
const h = c ?? (c ?? 'hello') // 0350
const i = c ?? b ?? 'hello' // 0400
`,
[{"start":0,"end":449,"count":1},
{"start":162,"end":167,"count":0},
{"start":262,"end":274,"count":0},
{"start":417,"end":427,"count":0}]);
TestCoverage(
"Optional Chaining",
`
const a = undefined || null // 0000
const b = a?.b // 0050
const c = a?.['b'] // 0100
const d = { // 0150
e: {f: 99, g: () => {return undefined}} // 0200
} // 0250
const e = d?.e?.f // 0300
const f = d?.e?.['f'] // 0350
const g = d?.e?.f?.g // 0400
const h = d?.e?.f?.g?.h // 0450
const i = d?.['d']?.['e']?.['h'] // 0500
const k = a?.('b') // 0550
const l = d?.e?.g?.() // 0600
const m = d?.e?.g?.()?.a?.b // 0650
delete a?.b // 0700
const n = d?.[d?.x?.f] // 0750
if (a?.[d?.x?.f]) { const p = 99 } else {}// 0800
const p = d?.[d?.x?.f]?.x // 0850
`,
[{"start":0,"end":899,"count":1},
{"start":61,"end":64,"count":0},
{"start":111,"end":118,"count":0},
{"start":470,"end":473,"count":0},
{"start":518,"end":532,"count":0},
{"start":561,"end":568,"count":0},
{"start":671,"end":677,"count":0},
{"start":708,"end":711,"count":0},
{"start":768,"end":771,"count":0},
{"start":805,"end":816,"count":0},
{"start":818,"end":834,"count":0},
{"start":868,"end":871,"count":0},
{"start":872,"end":875,"count":0},
{"start":216,"end":240,"count":2}]);
[coverage] Block coverage with support for IfStatements 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}
2017-06-06 15:44:55 +00:00
%DebugToggleBlockCoverage(false);