зеркало из https://github.com/mozilla/gecko-dev.git
Bug 813836: Optimize comparisons of single-element strings. r=jandem
This commit is contained in:
Родитель
0e3ad61a5d
Коммит
f1e256e606
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче