| Index: src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/codegen-ia32.cc (revision 4991)
|
| +++ src/ia32/codegen-ia32.cc (working copy)
|
| @@ -11656,7 +11656,7 @@
|
|
|
|
|
| void CompareStub::Generate(MacroAssembler* masm) {
|
| - Label call_builtin, done;
|
| + Label check_unequal_objects, done;
|
|
|
| // NOTICE! This code is only reached after a smi-fast-case check, so
|
| // it is certain that at least one operand isn't a smi.
|
| @@ -11734,79 +11734,75 @@
|
| __ bind(¬_identical);
|
| }
|
|
|
| - if (cc_ == equal) { // Both strict and non-strict.
|
| + // Strict equality can quickly decide whether objects are equal.
|
| + // Non-strict object equality is slower, so it is handled later in the stub.
|
| + if (cc_ == equal && strict_) {
|
| Label slow; // Fallthrough label.
|
| -
|
| + Label not_smis;
|
| // If we're doing a strict equality comparison, we don't have to do
|
| // type conversion, so we generate code to do fast comparison for objects
|
| // and oddballs. Non-smi numbers and strings still go through the usual
|
| // slow-case code.
|
| - if (strict_) {
|
| - // If either is a Smi (we know that not both are), then they can only
|
| - // be equal if the other is a HeapNumber. If so, use the slow case.
|
| - {
|
| - Label not_smis;
|
| - ASSERT_EQ(0, kSmiTag);
|
| - ASSERT_EQ(0, Smi::FromInt(0));
|
| - __ mov(ecx, Immediate(kSmiTagMask));
|
| - __ and_(ecx, Operand(eax));
|
| - __ test(ecx, Operand(edx));
|
| - __ j(not_zero, ¬_smis);
|
| - // One operand is a smi.
|
| + // If either is a Smi (we know that not both are), then they can only
|
| + // be equal if the other is a HeapNumber. If so, use the slow case.
|
| + ASSERT_EQ(0, kSmiTag);
|
| + ASSERT_EQ(0, Smi::FromInt(0));
|
| + __ mov(ecx, Immediate(kSmiTagMask));
|
| + __ and_(ecx, Operand(eax));
|
| + __ test(ecx, Operand(edx));
|
| + __ j(not_zero, ¬_smis);
|
| + // One operand is a smi.
|
|
|
| - // Check whether the non-smi is a heap number.
|
| - ASSERT_EQ(1, kSmiTagMask);
|
| - // ecx still holds eax & kSmiTag, which is either zero or one.
|
| - __ sub(Operand(ecx), Immediate(0x01));
|
| - __ mov(ebx, edx);
|
| - __ xor_(ebx, Operand(eax));
|
| - __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx.
|
| - __ xor_(ebx, Operand(eax));
|
| - // if eax was smi, ebx is now edx, else eax.
|
| + // Check whether the non-smi is a heap number.
|
| + ASSERT_EQ(1, kSmiTagMask);
|
| + // ecx still holds eax & kSmiTag, which is either zero or one.
|
| + __ sub(Operand(ecx), Immediate(0x01));
|
| + __ mov(ebx, edx);
|
| + __ xor_(ebx, Operand(eax));
|
| + __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx.
|
| + __ xor_(ebx, Operand(eax));
|
| + // if eax was smi, ebx is now edx, else eax.
|
|
|
| - // Check if the non-smi operand is a heap number.
|
| - __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
|
| - Immediate(Factory::heap_number_map()));
|
| - // If heap number, handle it in the slow case.
|
| - __ j(equal, &slow);
|
| - // Return non-equal (ebx is not zero)
|
| - __ mov(eax, ebx);
|
| - __ ret(0);
|
| + // Check if the non-smi operand is a heap number.
|
| + __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
|
| + Immediate(Factory::heap_number_map()));
|
| + // If heap number, handle it in the slow case.
|
| + __ j(equal, &slow);
|
| + // Return non-equal (ebx is not zero)
|
| + __ mov(eax, ebx);
|
| + __ ret(0);
|
|
|
| - __ bind(¬_smis);
|
| - }
|
| + __ bind(¬_smis);
|
| + // If either operand is a JSObject or an oddball value, then they are not
|
| + // equal since their pointers are different
|
| + // There is no test for undetectability in strict equality.
|
|
|
| - // If either operand is a JSObject or an oddball value, then they are not
|
| - // equal since their pointers are different
|
| - // There is no test for undetectability in strict equality.
|
| + // Get the type of the first operand.
|
| + // If the first object is a JS object, we have done pointer comparison.
|
| + Label first_non_object;
|
| + ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
| + __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
|
| + __ j(below, &first_non_object);
|
|
|
| - // Get the type of the first operand.
|
| - // If the first object is a JS object, we have done pointer comparison.
|
| - Label first_non_object;
|
| - ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
| - __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
|
| - __ j(below, &first_non_object);
|
| + // Return non-zero (eax is not zero)
|
| + Label return_not_equal;
|
| + ASSERT(kHeapObjectTag != 0);
|
| + __ bind(&return_not_equal);
|
| + __ ret(0);
|
|
|
| - // Return non-zero (eax is not zero)
|
| - Label return_not_equal;
|
| - ASSERT(kHeapObjectTag != 0);
|
| - __ bind(&return_not_equal);
|
| - __ ret(0);
|
| + __ bind(&first_non_object);
|
| + // Check for oddballs: true, false, null, undefined.
|
| + __ CmpInstanceType(ecx, ODDBALL_TYPE);
|
| + __ j(equal, &return_not_equal);
|
|
|
| - __ bind(&first_non_object);
|
| - // Check for oddballs: true, false, null, undefined.
|
| - __ CmpInstanceType(ecx, ODDBALL_TYPE);
|
| - __ j(equal, &return_not_equal);
|
| + __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx);
|
| + __ j(above_equal, &return_not_equal);
|
|
|
| - __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx);
|
| - __ j(above_equal, &return_not_equal);
|
| + // Check for oddballs: true, false, null, undefined.
|
| + __ CmpInstanceType(ecx, ODDBALL_TYPE);
|
| + __ j(equal, &return_not_equal);
|
|
|
| - // Check for oddballs: true, false, null, undefined.
|
| - __ CmpInstanceType(ecx, ODDBALL_TYPE);
|
| - __ j(equal, &return_not_equal);
|
| -
|
| - // Fall through to the general case.
|
| - }
|
| + // Fall through to the general case.
|
| __ bind(&slow);
|
| }
|
|
|
| @@ -11893,7 +11889,8 @@
|
|
|
| __ bind(&check_for_strings);
|
|
|
| - __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &call_builtin);
|
| + __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
|
| + &check_unequal_objects);
|
|
|
| // Inline comparison of ascii strings.
|
| StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
|
| @@ -11906,7 +11903,44 @@
|
| __ Abort("Unexpected fall-through from string comparison");
|
| #endif
|
|
|
| - __ bind(&call_builtin);
|
| + __ bind(&check_unequal_objects);
|
| + if (cc_ == equal && !strict_) {
|
| + // Non-strict equality. Objects are unequal if
|
| + // they are both JSObjects and not undetectable,
|
| + // and their pointers are different.
|
| + Label not_both_objects;
|
| + Label return_unequal;
|
| + // At most one is a smi, so we can test for smi by adding the two.
|
| + // A smi plus a heap object has the low bit set, a heap object plus
|
| + // a heap object has the low bit clear.
|
| + ASSERT_EQ(0, kSmiTag);
|
| + ASSERT_EQ(1, kSmiTagMask);
|
| + __ lea(ecx, Operand(eax, edx, times_1, 0));
|
| + __ test(ecx, Immediate(kSmiTagMask));
|
| + __ j(not_zero, ¬_both_objects);
|
| + __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
|
| + __ j(below, ¬_both_objects);
|
| + __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ebx);
|
| + __ j(below, ¬_both_objects);
|
| + // We do not bail out after this point. Both are JSObjects, and
|
| + // they are equal if and only if both are undetectable.
|
| + // The and of the undetectable flags is 1 if and only if they are equal.
|
| + __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
|
| + 1 << Map::kIsUndetectable);
|
| + __ j(zero, &return_unequal);
|
| + __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
|
| + 1 << Map::kIsUndetectable);
|
| + __ j(zero, &return_unequal);
|
| + // The objects are both undetectable, so they both compare as the value
|
| + // undefined, and are equal.
|
| + __ Set(eax, Immediate(EQUAL));
|
| + __ bind(&return_unequal);
|
| + // Return non-equal by returning the non-zero object pointer in eax,
|
| + // or return equal if we fell through to here.
|
| + __ ret(2 * kPointerSize); // rax, rdx were pushed
|
| + __ bind(¬_both_objects);
|
| + }
|
| +
|
| // must swap argument order
|
| __ pop(ecx);
|
| __ pop(edx);
|
|
|