blob: e3746acd17778e90a88341017a3724a7104ee55e [file] [edit]
// Coverage for the baseline JIT's inline atom-pointer dispatch of op_switch_string and the
// reachability of the slow path for other shapes.
function shouldBe(actual, expected, tag, detail) {
if (actual !== expected) {
let where = detail === undefined ? tag : `${tag} [${String(detail)}]`;
throw new Error(`${where}: expected ${String(expected)} but got ${String(actual)}`);
}
}
function nonAtomCopyOf(string) {
return string.split("").join("");
}
function nonAtomWideCopyOf(string) {
return $vm.make16BitStringIfPossible(string);
}
function unresolvedRope(left, right) {
return left + right;
}
const scrutineesThatMustTakeDefault = [
42, -0, 1.5, NaN, Infinity, true, false, null, undefined, 0n,
Symbol("alpha"), { toString() { return "alpha"; } }, ["alpha"], () => "alpha",
];
function switchOnMixedLengthKeys(scrutinee) {
switch (scrutinee) {
case "": return "empty";
case "a": return "a";
case "alpha": return "alpha";
case "alphabet": return "alphabet";
default: return "default";
}
}
noInline(switchOnMixedLengthKeys);
function switchOnNonLatin1Keys(scrutinee) {
switch (scrutinee) {
case "café": return "cafe";
case "日本": return "japan";
case "plain": return "plain";
default: return "default";
}
}
noInline(switchOnNonLatin1Keys);
const minimumTableSwitchCaseCount = 3;
const defaultInlineCaseCap = 64;
const caseCountsStraddlingInlineCap = [
minimumTableSwitchCaseCount,
defaultInlineCaseCap - 1,
defaultInlineCaseCap,
defaultInlineCaseCap + 1,
100,
];
const generatedSwitches = caseCountsStraddlingInlineCap.map(caseCount => {
let clauses = "";
let keyLiterals = [];
for (let i = 0; i < caseCount; ++i) {
clauses += `case "key${i}": return ${i};`;
keyLiterals.push(`"key${i}"`);
}
let { switchFunction, atomKeys } = new Function(`
const switchFunction = function (scrutinee) {
switch (scrutinee) { ${clauses} default: return -1; }
};
return { switchFunction, atomKeys: [${keyLiterals.join(",")}] };
`)();
noInline(switchFunction);
return { caseCount, switchFunction, atomKeys };
});
for (let i = 0; i < testLoopCount; ++i) {
shouldBe(switchOnMixedLengthKeys(""), "empty", "empty atom key");
shouldBe(switchOnMixedLengthKeys("a"), "a", "one-character atom key");
shouldBe(switchOnMixedLengthKeys("alpha"), "alpha", "atom key");
shouldBe(switchOnMixedLengthKeys("alphabet"), "alphabet", "longest atom key");
shouldBe(switchOnMixedLengthKeys("beta"), "default", "atom miss");
shouldBe(switchOnMixedLengthKeys(nonAtomCopyOf("alpha")), "alpha", "non-atom hit");
shouldBe(switchOnMixedLengthKeys(nonAtomCopyOf("beta")), "default", "non-atom miss");
shouldBe(switchOnMixedLengthKeys(nonAtomWideCopyOf("alpha")), "alpha", "wide copy of 8-bit key");
shouldBe(switchOnMixedLengthKeys(unresolvedRope("alph", "abet")), "alphabet", "rope hit");
shouldBe(switchOnMixedLengthKeys(unresolvedRope("bet", "a")), "default", "rope miss");
shouldBe(switchOnMixedLengthKeys(unresolvedRope("alphabet", "s")), "default", "rope longer than every key");
shouldBe(switchOnNonLatin1Keys("café"), "cafe", "16-bit atom key");
shouldBe(switchOnNonLatin1Keys("日本"), "japan", "non-Latin1 atom key");
shouldBe(switchOnNonLatin1Keys(nonAtomCopyOf("café")), "cafe", "non-atom 16-bit hit");
shouldBe(switchOnNonLatin1Keys(unresolvedRope("caf", "é")), "cafe", "16-bit rope hit");
shouldBe(switchOnNonLatin1Keys("plain"), "plain", "8-bit key among 16-bit keys");
for (const scrutinee of scrutineesThatMustTakeDefault) {
shouldBe(switchOnMixedLengthKeys(scrutinee), "default", "non-string scrutinee", scrutinee);
shouldBe(switchOnNonLatin1Keys(scrutinee), "default", "non-string scrutinee, 16-bit keys", scrutinee);
}
for (const { caseCount, switchFunction, atomKeys } of generatedSwitches) {
shouldBe(switchFunction(atomKeys[0]), 0, "first key", caseCount);
shouldBe(switchFunction(atomKeys[caseCount >> 1]), caseCount >> 1, "middle key", caseCount);
shouldBe(switchFunction(atomKeys[caseCount - 1]), caseCount - 1, "last key", caseCount);
shouldBe(switchFunction("nope"), -1, "miss", caseCount);
shouldBe(switchFunction(nonAtomCopyOf(atomKeys[caseCount - 1])), caseCount - 1, "non-atom hit", caseCount);
shouldBe(switchFunction(nonAtomWideCopyOf(atomKeys[0])), 0, "wide copy hit", caseCount);
shouldBe(switchFunction(unresolvedRope("key", "0")), 0, "rope hit", caseCount);
shouldBe(switchFunction(unresolvedRope("key", "nope")), -1, "rope miss", caseCount);
for (const scrutinee of scrutineesThatMustTakeDefault)
shouldBe(switchFunction(scrutinee), -1, "non-string scrutinee", caseCount);
}
}