| Index: src/arm/codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/codegen-arm.cc (revision 3561)
|
| +++ src/arm/codegen-arm.cc (working copy)
|
| @@ -44,7 +44,8 @@
|
|
|
| static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
| Label* slow,
|
| - Condition cc);
|
| + Condition cc,
|
| + bool never_nan_nan);
|
| static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
| Label* rhs_not_nan,
|
| Label* slow,
|
| @@ -4598,47 +4599,55 @@
|
| // for "identity and not NaN".
|
| static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
| Label* slow,
|
| - Condition cc) {
|
| + Condition cc,
|
| + bool never_nan_nan) {
|
| Label not_identical;
|
| + Label heap_number, return_equal;
|
| + Register exp_mask_reg = r5;
|
| __ cmp(r0, Operand(r1));
|
| __ b(ne, ¬_identical);
|
|
|
| - Register exp_mask_reg = r5;
|
| - __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask));
|
| + // The two objects are identical. If we know that one of them isn't NaN then
|
| + // we now know they test equal.
|
| + if (cc != eq || !never_nan_nan) {
|
| + __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask));
|
|
|
| - // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
|
| - // so we do the second best thing - test it ourselves.
|
| - Label heap_number, return_equal;
|
| - // They are both equal and they are not both Smis so both of them are not
|
| - // Smis. If it's not a heap number, then return equal.
|
| - if (cc == lt || cc == gt) {
|
| - __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE);
|
| - __ b(ge, slow);
|
| - } else {
|
| - __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
|
| - __ b(eq, &heap_number);
|
| - // Comparing JS objects with <=, >= is complicated.
|
| - if (cc != eq) {
|
| - __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
|
| + // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
|
| + // so we do the second best thing - test it ourselves.
|
| + // They are both equal and they are not both Smis so both of them are not
|
| + // Smis. If it's not a heap number, then return equal.
|
| + if (cc == lt || cc == gt) {
|
| + __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE);
|
| __ b(ge, slow);
|
| - // Normally here we fall through to return_equal, but undefined is
|
| - // special: (undefined == undefined) == true, but (undefined <= undefined)
|
| - // == false! See ECMAScript 11.8.5.
|
| - if (cc == le || cc == ge) {
|
| - __ cmp(r4, Operand(ODDBALL_TYPE));
|
| - __ b(ne, &return_equal);
|
| - __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
| - __ cmp(r0, Operand(r2));
|
| - __ b(ne, &return_equal);
|
| - if (cc == le) {
|
| - __ mov(r0, Operand(GREATER)); // undefined <= undefined should fail.
|
| - } else {
|
| - __ mov(r0, Operand(LESS)); // undefined >= undefined should fail.
|
| + } else {
|
| + __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
|
| + __ b(eq, &heap_number);
|
| + // Comparing JS objects with <=, >= is complicated.
|
| + if (cc != eq) {
|
| + __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
|
| + __ b(ge, slow);
|
| + // Normally here we fall through to return_equal, but undefined is
|
| + // special: (undefined == undefined) == true, but
|
| + // (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
| + if (cc == le || cc == ge) {
|
| + __ cmp(r4, Operand(ODDBALL_TYPE));
|
| + __ b(ne, &return_equal);
|
| + __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
| + __ cmp(r0, Operand(r2));
|
| + __ b(ne, &return_equal);
|
| + if (cc == le) {
|
| + // undefined <= undefined should fail.
|
| + __ mov(r0, Operand(GREATER));
|
| + } else {
|
| + // undefined >= undefined should fail.
|
| + __ mov(r0, Operand(LESS));
|
| + }
|
| + __ mov(pc, Operand(lr)); // Return.
|
| }
|
| - __ mov(pc, Operand(lr)); // Return.
|
| }
|
| }
|
| }
|
| +
|
| __ bind(&return_equal);
|
| if (cc == lt) {
|
| __ mov(r0, Operand(GREATER)); // Things aren't less than themselves.
|
| @@ -4649,43 +4658,45 @@
|
| }
|
| __ mov(pc, Operand(lr)); // Return.
|
|
|
| - // For less and greater we don't have to check for NaN since the result of
|
| - // x < x is false regardless. For the others here is some code to check
|
| - // for NaN.
|
| - if (cc != lt && cc != gt) {
|
| - __ bind(&heap_number);
|
| - // It is a heap number, so return non-equal if it's NaN and equal if it's
|
| - // not NaN.
|
| - // The representation of NaN values has all exponent bits (52..62) set,
|
| - // and not all mantissa bits (0..51) clear.
|
| - // Read top bits of double representation (second word of value).
|
| - __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
|
| - // Test that exponent bits are all set.
|
| - __ and_(r3, r2, Operand(exp_mask_reg));
|
| - __ cmp(r3, Operand(exp_mask_reg));
|
| - __ b(ne, &return_equal);
|
| + if (cc != eq || !never_nan_nan) {
|
| + // For less and greater we don't have to check for NaN since the result of
|
| + // x < x is false regardless. For the others here is some code to check
|
| + // for NaN.
|
| + if (cc != lt && cc != gt) {
|
| + __ bind(&heap_number);
|
| + // It is a heap number, so return non-equal if it's NaN and equal if it's
|
| + // not NaN.
|
| + // The representation of NaN values has all exponent bits (52..62) set,
|
| + // and not all mantissa bits (0..51) clear.
|
| + // Read top bits of double representation (second word of value).
|
| + __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
|
| + // Test that exponent bits are all set.
|
| + __ and_(r3, r2, Operand(exp_mask_reg));
|
| + __ cmp(r3, Operand(exp_mask_reg));
|
| + __ b(ne, &return_equal);
|
|
|
| - // Shift out flag and all exponent bits, retaining only mantissa.
|
| - __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
|
| - // Or with all low-bits of mantissa.
|
| - __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
|
| - __ orr(r0, r3, Operand(r2), SetCC);
|
| - // For equal we already have the right value in r0: Return zero (equal)
|
| - // if all bits in mantissa are zero (it's an Infinity) and non-zero if not
|
| - // (it's a NaN). For <= and >= we need to load r0 with the failing value
|
| - // if it's a NaN.
|
| - if (cc != eq) {
|
| - // All-zero means Infinity means equal.
|
| - __ mov(pc, Operand(lr), LeaveCC, eq); // Return equal
|
| - if (cc == le) {
|
| - __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
|
| - } else {
|
| - __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
|
| + // Shift out flag and all exponent bits, retaining only mantissa.
|
| + __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
|
| + // Or with all low-bits of mantissa.
|
| + __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
|
| + __ orr(r0, r3, Operand(r2), SetCC);
|
| + // For equal we already have the right value in r0: Return zero (equal)
|
| + // if all bits in mantissa are zero (it's an Infinity) and non-zero if not
|
| + // (it's a NaN). For <= and >= we need to load r0 with the failing value
|
| + // if it's a NaN.
|
| + if (cc != eq) {
|
| + // All-zero means Infinity means equal.
|
| + __ mov(pc, Operand(lr), LeaveCC, eq); // Return equal
|
| + if (cc == le) {
|
| + __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
|
| + } else {
|
| + __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
|
| + }
|
| }
|
| + __ mov(pc, Operand(lr)); // Return.
|
| }
|
| - __ mov(pc, Operand(lr)); // Return.
|
| - }
|
| - // No fall through here.
|
| + // No fall through here.
|
| + }
|
|
|
| __ bind(¬_identical);
|
| }
|
| @@ -4911,12 +4922,13 @@
|
| // Fast negative check for symbol-to-symbol equality.
|
| static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) {
|
| // r2 is object type of r0.
|
| - __ tst(r2, Operand(kIsNotStringMask));
|
| - __ b(ne, slow);
|
| + // Ensure that no non-strings have the symbol bit set.
|
| + ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE);
|
| + ASSERT(kSymbolTag != 0);
|
| __ tst(r2, Operand(kIsSymbolMask));
|
| __ b(eq, slow);
|
| - __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
|
| - __ b(ge, slow);
|
| + ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
|
| + ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
|
| __ tst(r3, Operand(kIsSymbolMask));
|
| __ b(eq, slow);
|
|
|
| @@ -4938,7 +4950,7 @@
|
|
|
| // Handle the case where the objects are identical. Either returns the answer
|
| // or goes to slow. Only falls through if the objects were not identical.
|
| - EmitIdenticalObjectComparison(masm, &slow, cc_);
|
| + EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
|
|
|
| // If either is a Smi (we know that not both are), then they can only
|
| // be strictly equal if the other is a HeapNumber.
|
| @@ -6487,10 +6499,53 @@
|
| }
|
|
|
|
|
| +const char* CompareStub::GetName() {
|
| + switch(cc_) {
|
| + case lt: return "CompareStub_LT";
|
| + case gt: return "CompareStub_GT";
|
| + case le: return "CompareStub_LE";
|
| + case ge: return "CompareStub_GE";
|
| + case ne: {
|
| + if (strict_) {
|
| + if (never_nan_nan_) {
|
| + return "CompareStub_NE_STRICT_NO_NAN";
|
| + } else {
|
| + return "CompareStub_NE_STRICT";
|
| + }
|
| + } else {
|
| + if (never_nan_nan_) {
|
| + return "CompareStub_NE_NO_NAN";
|
| + } else {
|
| + return "CompareStub_NE";
|
| + }
|
| + }
|
| + }
|
| + case eq: {
|
| + if (strict_) {
|
| + if (never_nan_nan_) {
|
| + return "CompareStub_EQ_STRICT_NO_NAN";
|
| + } else {
|
| + return "CompareStub_EQ_STRICT";
|
| + }
|
| + } else {
|
| + if (never_nan_nan_) {
|
| + return "CompareStub_EQ_NO_NAN";
|
| + } else {
|
| + return "CompareStub_EQ";
|
| + }
|
| + }
|
| + }
|
| + default: return "CompareStub";
|
| + }
|
| +}
|
| +
|
| +
|
| int CompareStub::MinorKey() {
|
| - // Encode the two parameters in a unique 16 bit value.
|
| - ASSERT(static_cast<unsigned>(cc_) >> 28 < (1 << 15));
|
| - return (static_cast<unsigned>(cc_) >> 27) | (strict_ ? 1 : 0);
|
| + // Encode the three parameters in a unique 16 bit value.
|
| + ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
|
| + int nnn_value = (never_nan_nan_ ? 2 : 0);
|
| + if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs.
|
| + return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0);
|
| }
|
|
|
|
|
|
|