// |jit-test| --code-coverage // Currently the Jit integration has a few issues, let's keep this test // case deterministic. // // - Baseline OSR increments the loop header twice. // - Ion is not updating any counter yet. // if (getJitCompilerOptions()["ion.warmup.trigger"] != 30) setJitCompilerOption("ion.warmup.trigger", 30); if (getJitCompilerOptions()["baseline.warmup.trigger"] != 10) setJitCompilerOption("baseline.warmup.trigger", 10); /* * These test cases are annotated with the output produced by LCOV [1]. Comment * starting with // without any spaces are used as a reference for the code * coverage output. Any "$" in these line comments are replaced by the current * line number, and any "%" are replaced with the current function name (defined * by the FN key). * * [1] http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php */ function checkLcov(fun) { var keys = [ "TN", "SF", "FN", "FNDA", "FNF", "FNH", "BRDA", "BRF", "BRH", "DA", "LF", "LH" ]; function startsWithKey(s) { for (k of keys) { if (s.startsWith(k)) return true; } return false; }; // Extract the body of the function, as the code to be executed. var source = fun.toString(); source = source.slice(source.indexOf('{') + 1, source.lastIndexOf('}')); // Extract comment starting with the previous keys, as a reference of the // output expected from getLcovInfo. var lcovRef = []; var currLine = 0; var currFun = ""; for (var line of source.split('\n')) { currLine++; for (var comment of line.split("//").slice(1)) { if (!startsWithKey(comment)) continue; comment = comment.trim(); if (comment.startsWith("FN:")) currFun = comment.split(',')[1]; comment = comment.replace('$', currLine); comment = comment.replace('%', currFun); lcovRef.push(comment); } } // Evaluate the code, and generate the Lcov result from the execution. We have // to disable lazy parsing, as we rely on the ZoneCellIter to emulate the // behaviour of the finalizer. var g = newGlobal({ disableLazyParsing: true }); g.eval(source); var lcovResRaw = getLcovInfo(g); // Check that all the lines are present the result. var lcovRes = lcovResRaw.split('\n'); for (ref of lcovRef) { if (lcovRes.indexOf(ref) == -1) { print("Cannot find `" + ref + "` in the following Lcov result:\n", lcovResRaw); print("In the following source:\n", source); assertEq(true, false); } } } checkLcov(function () { //FN:$,top-level //FNDA:1,% ",".split(','); //DA:$,1 //FNF:1 //FNH:1 //LF:1 //LH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% function f() { //FN:$,f ",".split(','); //DA:$,0 } ",".split(','); //DA:$,1 //FNF:2 //FNH:1 //LF:2 //LH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% function f() { //FN:$,f //FNDA:1,% ",".split(','); //DA:$,1 } f(); //DA:$,1 //FNF:2 //FNH:2 //LF:2 //LH:2 }); checkLcov(function () { ','.split(','); //FN:$,top-level //FNDA:1,% //DA:$,1 //FNF:1 //FNH:1 //LF:1 //LH:1 }); checkLcov(function () { function f() { ','.split(','); } //FN:$,top-level //FNDA:1,% //FN:$,f //FNDA:1,f //DA:$,1 f(); //DA:$,1 //FNF:2 //FNH:2 //LF:2 //LH:2 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 if (l.length == 3) //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0 l.push(''); //DA:$,0 l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:4 //LH:3 //BRF:2 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 if (l.length == 2) //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 l.push(''); //DA:$,1 l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:4 //LH:4 //BRF:2 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 if (l.length == 3) //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0 l.push(''); //DA:$,0 else l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:4 //LH:3 //BRF:2 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 if (l.length == 2) //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 l.push(''); //DA:$,1 else l.pop(); //DA:$,0 //FNF:1 //FNH:1 //LF:4 //LH:3 //BRF:2 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 if (l.length == 2) //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 l.push(''); //DA:$,1 else { if (l.length == 1) //DA:$,0 //BRDA:$,1,0,- //BRDA:$,1,1,- l.pop(); //DA:$,0 } //FNF:1 //FNH:1 //LF:5 //LH:3 //BRF:4 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% function f(i) { //FN:$,f //FNDA:2,% var x = 0; //DA:$,2 while (i--) { // Currently OSR wrongly count the loop header twice. // So instead of DA:$,12 , we have DA:$,13 . x += i; //DA:$,10 x = x / 2; //DA:$,10 } return x; //DA:$,2 //BRF:2 //BRH:2 } f(5); //DA:$,1 f(5); //DA:$,1 //FNF:2 //FNH:2 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% try { //DA:$,1 var l = ",".split(','); //DA:$,1 if (l.length == 2) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 l.push(''); //DA:$,1 throw l; //DA:$,1 } l.pop(); //DA:$,0 } catch (x) { //DA:$,1 x.pop(); //DA:$,1 } //FNF:1 //FNH:1 //LF:8 //LH:7 //BRF:2 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 try { //DA:$,1 try { //DA:$,1 if (l.length == 2) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 l.push(''); //DA:$,1 throw l; //DA:$,1 } l.pop(); //DA:$,0 } finally { //DA:$,1 l.pop(); //DA:$,1 } } catch (x) { //DA:$,1 } //FNF:1 //FNH:1 //LF:10 //LH:9 //BRF:2 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% function f() { //FN:$,f //FNDA:1,% throw 1; //DA:$,1 f(); //DA:$,0 } var l = ",".split(','); //DA:$,1 try { //DA:$,1 f(); //DA:$,1 f(); //DA:$,0 } catch (x) { //DA:$,1 } //FNF:2 //FNH:2 //LF:7 //LH:5 //BRF:0 //BRH:0 }); // Test TableSwitch opcode checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 //BRDA:$,0,4,0 case 0: l.push('0'); //DA:$,0 break; case 1: l.push('1'); //DA:$,0 break; case 2: l.push('2'); //DA:$,1 break; case 3: l.push('3'); //DA:$,0 break; } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:4 //BRF:5 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 //BRDA:$,0,4,0 case 0: l.push('0'); //DA:$,0 case 1: l.push('1'); //DA:$,0 case 2: l.push('2'); //DA:$,1 case 3: l.push('3'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:5 //BRF:5 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 // Branches are ordered, and starting at 0 switch (l.length) { //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0 //BRDA:$,0,2,0 //BRDA:$,0,3,0 //BRDA:$,0,4,0 case 5: l.push('5'); //DA:$,0 case 4: l.push('4'); //DA:$,0 case 3: l.push('3'); //DA:$,0 case 2: l.push('2'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:4 //BRF:5 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0 //BRDA:$,0,2,0 case 2: l.push('2'); //DA:$,1 case 5: l.push('5'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:5 //LH:5 //BRF:3 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 //BRDA:$,0,2,0 case 3: l.push('1'); //DA:$,0 case 5: l.push('5'); //DA:$,0 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:5 //LH:3 //BRF:3 //BRH:1 }); // Unfortunately the differences between switch implementations leaks in the // code coverage reports. checkLcov(function () { //FN:$,top-level //FNDA:1,% function f(a) { //FN:$,f //FNDA:2,% return a; //DA:$,2 } var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 case f(-42): //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 l.push('1'); //DA:$,0 case f(51): //DA:$,1 //BRDA:$,1,0,0 //BRDA:$,1,1,1 l.push('5'); //DA:$,0 } l.pop(); //DA:$,1 //FNF:2 //FNH:2 //LF:8 //LH:6 //BRF:4 //BRH:2 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 //BRDA:$,0,2,0 //BRDA:$,0,3,0 case 0: case 1: l.push('0'); //DA:$,0 l.push('1'); //DA:$,0 case 2: l.push('2'); //DA:$,1 case 3: l.push('3'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:5 //BRF:4 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 case 0: l.push('0'); //DA:$,0 case 1: l.push('1'); //DA:$,0 case 2: case 3: l.push('2'); //DA:$,1 l.push('3'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:5 //BRF:4 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 case 0: l.push('0'); //DA:$,0 case 1: default: l.push('1'); //DA:$,0 case 2: l.push('2'); //DA:$,1 case 3: l.push('3'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:5 //BRF:4 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 case 0: l.push('0'); //DA:$,0 case 1: l.push('1'); //DA:$,0 default: case 2: l.push('2'); //DA:$,1 case 3: l.push('3'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:5 //BRF:4 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 //BRDA:$,0,4,0 case 0: l.push('0'); //DA:$,0 case 1: l.push('1'); //DA:$,0 default: l.push('default'); //DA:$,0 case 2: l.push('2'); //DA:$,1 case 3: l.push('3'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:8 //LH:5 //BRF:5 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ",".split(','); //DA:$,1 switch (l.length) { //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 case 0: l.push('0'); //DA:$,0 case 1: l.push('1'); //DA:$,0 default: l.push('2'); //DA:$,1 case 3: l.push('3'); //DA:$,1 } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:7 //LH:5 //BRF:4 //BRH:1 }); checkLcov(function () { //FN:$,top-level //FNDA:1,% var l = ','.split(','); //DA:$,1 if (l.length === 45) { //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0 switch (l[0]) { //DA:$,0 //BRDA:$,1,0,- //BRDA:$,1,1,- case ',': l.push('0'); //DA:$,0 default: l.push('1'); //DA:$,0 } } l.pop(); //DA:$,1 //FNF:1 //FNH:1 //LF:6 //LH:3 //BRF:4 //BRH:1 }); // These tests are not included in ../debug/Script-getOffsetsCoverage-01.js // because we're specifically testing a feature of Lcov output that // Debugger.Script doesn't have (the aggregation of hits that are on the // same line but in different functions). { checkLcov(function () { //FN:$,top-level //FNDA:1,% function f() { return 0; } var l = f(); //DA:$,2 //FNF:2 //FNH:2 //LF:1 //LH:1 }); // A single line has two functions on it, and both hit. checkLcov(function () { //FN:$,top-level //FNDA:1,% function f() { return 0; } function g() { return 1; } //DA:$,2 var v = f() + g(); //DA:$,1 //FNF:3 //FNH:3 //LF:2 //LH:2 }); // A line has both function code and toplevel code, and only one of them hits. checkLcov(function () { //FN:$,top-level //FNDA:1,% if (1 === 2) //DA:$,1 throw "0 hits here"; function f() { return "1 hit here"; } //DA:$,1 f(); //DA:$,1 //FNF:2 //FNH:2 //LF:3 //LH:3 }); } // These tests are not included in ../debug/Script-getOffsetsCoverage-01.js // because they are testing behaviour of --code-coverage. { // Test function names checkLcov(function () { //FN:1,top-level //FNDA:1,top-level var x = function() {}; //FN:$,x let y = function() {}; //FN:$,y let z = { z_method() { }, //FN:$,z_method get z_prop() { }, //FN:$,get z_prop } }); } // If you add a test case here, do the same in // jit-test/tests/debug/Script-getOffsetsCoverage-01.js