Bug 813836: Optimize comparisons of single-element strings. r=jandem

This commit is contained in:
André Bargull 2018-08-10 08:56:47 -07:00
Родитель 0e3ad61a5d
Коммит f1e256e606
4 изменённых файлов: 217 добавлений и 0 удалений

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

@ -73,6 +73,7 @@ namespace JS {
_(Compare_SpecializedOnBaselineTypes) \
_(Compare_SharedCache) \
_(Compare_Call) \
_(Compare_Character) \
\
_(Call_Inline)

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

@ -0,0 +1,147 @@
function IsASCIIAlphaString_CharCodeAt(s) {
for (var i = 0; i < s.length; i++) {
var c = s.charCodeAt(i);
if (!((0x41 <= c && c <= 0x5A) || (0x61 <= c && c <= 0x7A)))
return false;
}
return true;
}
function IsASCIIAlphaString_CharAt(s) {
for (var i = 0; i < s.length; i++) {
var c = s.charAt(i);
if (!(("A" <= c && c <= "Z") || ("a" <= c && c <= "z")))
return false;
}
return true;
}
function IsASCIIAlphaString_GetElem(s) {
for (var i = 0; i < s.length; i++) {
var c = s[i];
if (!(("A" <= c && c <= "Z") || ("a" <= c && c <= "z")))
return false;
}
return true;
}
function IsGreekOrCyrillicString_CharCodeAt(s) {
// U+0370 (GREEK CAPITAL LETTER HETA)
// U+03FF (GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL)
// U+0400 (CYRILLIC CAPITAL LETTER IE WITH GRAVE)
// U+052F (CYRILLIC SMALL LETTER EL WITH DESCENDER)
for (var i = 0; i < s.length; i++) {
var c = s.charCodeAt(i);
if (!((0x0370 <= c && c <= 0x03FF) || (0x400 <= c && c <= 0x052F)))
return false;
}
return true;
}
function IsGreekOrCyrillicString_CharAt(s) {
for (var i = 0; i < s.length; i++) {
var c = s.charAt(i);
if (!(("Ͱ" <= c && c <= "Ͽ") || ("Ѐ" <= c && c <= "ԯ")))
return false;
}
return true;
}
function IsGreekOrCyrillicString_GetElem(s) {
for (var i = 0; i < s.length; i++) {
var c = s[i];
if (!(("Ͱ" <= c && c <= "Ͽ") || ("Ѐ" <= c && c <= "ԯ")))
return false;
}
return true;
}
function main() {
function compareLatin1() {
var strings = ["ABCABCABC", "abcabcabc"];
var q = 0;
for (var i = 0; i < 200; ++i) {
var str = strings[i & 1];
for (var j = 0; j < str.length; ++j) {
if (str[j] === "a")
q++;
if ("A" == str[j])
q++;
if (str[j] != "b")
q++;
if ("D" !== str[j])
q++;
}
}
assertEq(q, 100*3 + 100*3 + 100*15 + 100*18);
}
function compareTwoByte() {
var strings = ["āĉœāĉœāĉœ", "abcabcabc"];
var q = 0;
for (var i = 0; i < 200; ++i) {
var str = strings[i & 1];
for (var j = 0; j < str.length; ++j) {
if ("œ" === str[j])
q++;
if (str[j] == "ĉ")
q++;
if ("ā" != str[j])
q++;
if (str[j] !== "Ɖ")
q++;
}
}
assertEq(q, 100*3 + 100*3 + 100*15 + 100*18);
}
function compareRangeLatin1() {
var strings = [
"ABCABCABC", // all upper
"abcabcabc", // all lower
"abcABCabc", // lower and upper
"abcabc123", // characters below limit
"abc[_]ABC", // characters between limit
"ABC{|}abc", // characters above limit
"!#$456_~ÿ", // no matches at all
"aBcZyyZUU", // -
];
for (var i = 0; i < 200; ++i) {
var str = strings[i & 7];
var resultCharCodeAt = IsASCIIAlphaString_CharCodeAt(str);
var resultCharAt = IsASCIIAlphaString_CharAt(str);
var resultGetElem = IsASCIIAlphaString_GetElem(str);
assertEq(resultCharAt, resultCharCodeAt);
assertEq(resultGetElem, resultCharCodeAt);
}
}
function compareRangeTwoByte() {
var strings = [
"αβγΑΒΓαβγ", // all Greek
"АБВабвАБВ", // all Cyrillic
"αβγабвАБΓ", // Greek and Cyrillic
"αβγāēōАБВ", // characters below limit
"αβγԱԲԳАБВ", // characters above limit
"abcāēōԱԲԳ", // no matches at all
"𝐀𝐁𝐂𝐀𝐁𝐂𝐀𝐁𝐂", // (non-BMP)
"abcabcabc", // -
];
for (var i = 0; i < 200; ++i) {
var str = strings[i & 7];
var resultCharCodeAt = IsGreekOrCyrillicString_CharCodeAt(str);
var resultCharAt = IsGreekOrCyrillicString_CharAt(str);
var resultGetElem = IsGreekOrCyrillicString_GetElem(str);
assertEq(resultCharAt, resultCharCodeAt);
assertEq(resultGetElem, resultCharCodeAt);
}
}
compareLatin1();
compareTwoByte();
compareRangeLatin1();
compareRangeTwoByte();
}
for (var i = 0; i < 15; ++i) {
main();
}

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

@ -5825,6 +5825,9 @@ IonBuilder::jsop_compare(JSOp op, MDefinition* left, MDefinition* right)
startTrackingOptimizations();
if (!forceInlineCaches()) {
MOZ_TRY(compareTryCharacter(&emitted, op, left, right));
if (emitted)
return Ok();
MOZ_TRY(compareTrySpecialized(&emitted, op, left, right));
if (emitted)
return Ok();
@ -5857,6 +5860,70 @@ IonBuilder::jsop_compare(JSOp op, MDefinition* left, MDefinition* right)
return Ok();
}
AbortReasonOr<Ok>
IonBuilder::compareTryCharacter(bool* emitted, JSOp op, MDefinition* left, MDefinition* right)
{
MOZ_ASSERT(*emitted == false);
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time. Currently just drop optimization
// tracking when that happens.
bool canTrackOptimization = !IsCallPC(pc);
if (canTrackOptimization)
trackOptimizationAttempt(TrackedStrategy::Compare_Character);
// Try to optimize |MConstant(string) <compare> (MFromCharCode MCharCodeAt)|
// as |MConstant(charcode) <compare> MCharCodeAt|.
MConstant* constant;
MDefinition* operand;
if (left->isConstant()) {
constant = left->toConstant();
operand = right;
} else if (right->isConstant()) {
constant = right->toConstant();
operand = left;
} else {
return Ok();
}
if (constant->type() != MIRType::String || constant->toString()->length() != 1)
return Ok();
if (!operand->isFromCharCode() || !operand->toFromCharCode()->input()->isCharCodeAt())
return Ok();
char16_t charCode = constant->toString()->asAtom().latin1OrTwoByteChar(0);
constant->setImplicitlyUsedUnchecked();
MConstant* charCodeConst = MConstant::New(alloc(), Int32Value(charCode));
current->add(charCodeConst);
MDefinition* charCodeAt = operand->toFromCharCode()->input();
operand->setImplicitlyUsedUnchecked();
if (left == constant) {
left = charCodeConst;
right = charCodeAt;
} else {
left = charCodeAt;
right = charCodeConst;
}
MCompare* ins = MCompare::New(alloc(), left, right, op);
ins->setCompareType(MCompare::Compare_Int32);
ins->cacheOperandMightEmulateUndefined(constraints());
current->add(ins);
current->push(ins);
MOZ_ASSERT(!ins->isEffectful());
if (canTrackOptimization)
trackOptimizationSuccess();
*emitted = true;
return Ok();
}
static bool
ObjectOrSimplePrimitive(MDefinition* op)
{

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

@ -333,6 +333,8 @@ class IonBuilder
MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> compareTryBinaryStub(bool* emitted, MDefinition* left, MDefinition* right);
AbortReasonOr<Ok> compareTryCharacter(bool* emitted, JSOp op, MDefinition* left,
MDefinition* right);
// jsop_newarray helpers.
AbortReasonOr<Ok> newArrayTryTemplateObject(bool* emitted, JSObject* templateObject,