Bug 1304569 - JS Code Coverage: Simplify checks for the last found case-statement body. r=bhackett

This commit is contained in:
Nicolas B. Pierron 2017-07-20 16:20:14 +00:00
Родитель cd15c1d8a0
Коммит 30db580939
2 изменённых файлов: 50 добавлений и 8 удалений

Просмотреть файл

@ -0,0 +1,13 @@
s = newGlobal()
evalcx("\
switch (0) {\
default: break;\
case 1:\
this.s += this.s;\
g(h(\"\", 2));\
break;\
break\
}\
", s)
evalcx("getLcovInfo()", s)

Просмотреть файл

@ -171,6 +171,7 @@ LCovSource::writeScript(JSScript* script)
size_t branchId = 0; size_t branchId = 0;
size_t tableswitchExitOffset = 0; size_t tableswitchExitOffset = 0;
for (jsbytecode* pc = script->code(); pc != end; pc = GetNextPc(pc)) { for (jsbytecode* pc = script->code(); pc != end; pc = GetNextPc(pc)) {
MOZ_ASSERT(script->code() <= pc && pc < end);
JSOp op = JSOp(*pc); JSOp op = JSOp(*pc);
bool jump = IsJumpOpcode(op) || op == JSOP_TABLESWITCH; bool jump = IsJumpOpcode(op) || op == JSOP_TABLESWITCH;
bool fallsthrough = BytecodeFallsThrough(op) && op != JSOP_GOSUB; bool fallsthrough = BytecodeFallsThrough(op) && op != JSOP_GOSUB;
@ -257,6 +258,8 @@ LCovSource::writeScript(JSScript* script)
// Get the default and exit pc // Get the default and exit pc
jsbytecode* exitpc = pc + tableswitchExitOffset; jsbytecode* exitpc = pc + tableswitchExitOffset;
jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc); jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc);
MOZ_ASSERT(script->code() <= exitpc && exitpc <= end);
MOZ_ASSERT(script->code() <= defaultpc && defaultpc < end);
MOZ_ASSERT(defaultpc > pc && defaultpc <= exitpc); MOZ_ASSERT(defaultpc > pc && defaultpc <= exitpc);
// Get the low and high from the tableswitch // Get the low and high from the tableswitch
@ -269,6 +272,7 @@ LCovSource::writeScript(JSScript* script)
jsbytecode* firstcasepc = exitpc; jsbytecode* firstcasepc = exitpc;
for (size_t j = 0; j < numCases; j++) { for (size_t j = 0; j < numCases; j++) {
jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j); jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
MOZ_ASSERT(script->code() <= testpc && testpc < end);
if (testpc < firstcasepc) if (testpc < firstcasepc)
firstcasepc = testpc; firstcasepc = testpc;
} }
@ -284,19 +288,26 @@ LCovSource::writeScript(JSScript* script)
size_t caseId = 0; size_t caseId = 0;
for (size_t i = 0; i < numCases; i++) { for (size_t i = 0; i < numCases; i++) {
jsbytecode* casepc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * i); jsbytecode* casepc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * i);
MOZ_ASSERT(script->code() <= casepc && casepc < end);
// The case is not present, and jumps to the default pc if used. // The case is not present, and jumps to the default pc if used.
if (casepc == pc) if (casepc == pc)
continue; continue;
// PCs might not be in increasing order of case indexes. // PCs might not be in increasing order of case indexes.
jsbytecode* lastcasepc = firstcasepc - 1; jsbytecode* lastcasepc = firstcasepc - 1;
bool foundLastCase = false;
for (size_t j = 0; j < numCases; j++) { for (size_t j = 0; j < numCases; j++) {
jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j); jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
if (lastcasepc < testpc && (testpc < casepc || (j < i && testpc == casepc))) MOZ_ASSERT(script->code() <= testpc && testpc < end);
if (lastcasepc < testpc && (testpc < casepc || (j < i && testpc == casepc))) {
lastcasepc = testpc; lastcasepc = testpc;
foundLastCase = true;
}
} }
if (casepc != lastcasepc) { // If multiple case instruction have the same code block, only
// register the code coverage the first time we hit this case.
if (!foundLastCase || casepc != lastcasepc) {
// Case (i + low) // Case (i + low)
uint64_t caseHits = 0; uint64_t caseHits = 0;
if (sc) { if (sc) {
@ -306,10 +317,15 @@ LCovSource::writeScript(JSScript* script)
// Remove fallthrough. // Remove fallthrough.
fallsThroughHits = 0; fallsThroughHits = 0;
if (casepc != firstcasepc) { if (foundLastCase) {
// Walk from the previous case to the current one to
// check if it fallthrough into the current block.
MOZ_ASSERT(lastcasepc != firstcasepc - 1);
jsbytecode* endpc = lastcasepc; jsbytecode* endpc = lastcasepc;
while (GetNextPc(endpc) < casepc) while (GetNextPc(endpc) < casepc) {
endpc = GetNextPc(endpc); endpc = GetNextPc(endpc);
MOZ_ASSERT(script->code() <= endpc && endpc < end);
}
if (BytecodeFallsThrough(JSOp(*endpc))) if (BytecodeFallsThrough(JSOp(*endpc)))
fallsThroughHits = script->getHitCount(endpc); fallsThroughHits = script->getHitCount(endpc);
@ -340,22 +356,35 @@ LCovSource::writeScript(JSScript* script)
// Look for the last case entry before the default pc. // Look for the last case entry before the default pc.
jsbytecode* lastcasepc = firstcasepc - 1; jsbytecode* lastcasepc = firstcasepc - 1;
bool foundLastCase = false;
for (size_t j = 0; j < numCases; j++) { for (size_t j = 0; j < numCases; j++) {
jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j); jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
if (lastcasepc < testpc && testpc <= defaultpc) MOZ_ASSERT(script->code() <= testpc && testpc < end);
if (lastcasepc < testpc && testpc <= defaultpc) {
lastcasepc = testpc; lastcasepc = testpc;
foundLastCase = true;
}
} }
if (lastcasepc == defaultpc) // Set defaultHasOwnClause to false, if one of the case
// statement has the same pc as the default block. Which implies
// that the previous loop already encoded the coverage
// information for the current block.
if (foundLastCase && lastcasepc == defaultpc)
defaultHasOwnClause = false; defaultHasOwnClause = false;
// Look if the last case entry fallthrough to the default case, // Look if the last case entry fallthrough to the default case,
// in which case we have to remove the number of fallthrough // in which case we have to remove the number of fallthrough
// hits out of the default case hits. // hits out of the default case hits.
if (sc && lastcasepc != pc) { if (sc && foundLastCase) {
// Walk from the previous case to the current one to check
// if it fallthrough into the default block.
MOZ_ASSERT(lastcasepc != firstcasepc - 1);
jsbytecode* endpc = lastcasepc; jsbytecode* endpc = lastcasepc;
while (GetNextPc(endpc) < defaultpc) while (GetNextPc(endpc) < defaultpc) {
endpc = GetNextPc(endpc); endpc = GetNextPc(endpc);
MOZ_ASSERT(script->code() <= endpc && endpc < end);
}
if (BytecodeFallsThrough(JSOp(*endpc))) if (BytecodeFallsThrough(JSOp(*endpc)))
fallsThroughHits = script->getHitCount(endpc); fallsThroughHits = script->getHitCount(endpc);