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

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

1258 lines
46 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-turbofan --no-stress-flush-code
// Flags: --expose-gc
// Files: test/mjsunit/code-coverage-utils.js
(async function () {
[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);
await TestCoverage(
"call an IIFE",
`
[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
(function f() {})();
`,
[ {"start":0,"end":20,"count":1},
{"start":1,"end":16,"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
await 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
await 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
`,
[ {"start":0,"end":949,"count":1},
{"start":801,"end":901,"count":0},
{"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} ]
);
await 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
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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}
]);
await 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://crbug.com/785778
await 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} ]
);
await 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
await TestCoverage(
"https://crbug.com/v8/8237",
`
2018-10-10 12:44:11 +00:00
!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},
{"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},
{"start":851,"end":1001,"count":1},
{"start":920,"end":928,"count":0},
{"start":929,"end":965,"count":0} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await TestCoverage(
"https://crbug.com/v8/9857",
`function foo() {}`,
[ {"start":0,"end":17,"count":1},
{"start":0,"end":17,"count":0} ]
);
[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
await 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} ]
);
[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
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
await 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} ]
);
%DebugToggleBlockCoverage(false);
})();