Commit b122fbd3 authored by whesse@chromium.org's avatar whesse@chromium.org

Decide that different detectable objects are not equal without calling runtime, on all platforms.

Review URL: http://codereview.chromium.org/2805046

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4992 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6044b337
...@@ -7216,22 +7216,42 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, ...@@ -7216,22 +7216,42 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
// Fast negative check for symbol-to-symbol equality. // Fast negative check for symbol-to-symbol equality.
static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) { static void EmitCheckForSymbolsOrObjects(MacroAssembler* masm,
Label* possible_strings,
Label* not_both_strings) {
// r2 is object type of r0. // r2 is object type of r0.
// Ensure that no non-strings have the symbol bit set. // Ensure that no non-strings have the symbol bit set.
ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); Label object_test;
ASSERT(kSymbolTag != 0); ASSERT(kSymbolTag != 0);
__ tst(r2, Operand(kIsNotStringMask));
__ b(ne, &object_test);
__ tst(r2, Operand(kIsSymbolMask)); __ tst(r2, Operand(kIsSymbolMask));
__ b(eq, slow); __ b(eq, possible_strings);
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
__ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); __ b(ge, not_both_strings);
__ tst(r3, Operand(kIsSymbolMask)); __ tst(r3, Operand(kIsSymbolMask));
__ b(eq, slow); __ b(eq, possible_strings);
// Both are symbols. We already checked they weren't the same pointer // Both are symbols. We already checked they weren't the same pointer
// so they are not equal. // so they are not equal.
__ mov(r0, Operand(1)); // Non-zero indicates not equal. __ mov(r0, Operand(1)); // Non-zero indicates not equal.
__ mov(pc, Operand(lr)); // Return. __ mov(pc, Operand(lr)); // Return.
__ bind(&object_test);
__ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
__ b(lt, not_both_strings);
__ CompareObjectType(r1, r2, r3, FIRST_JS_OBJECT_TYPE);
__ b(lt, not_both_strings);
// If both objects are undetectable, they are equal. Otherwise, they
// are not equal, since they are different objects and an object is not
// equal to undefined.
__ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset));
__ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
__ and_(r0, r2, Operand(r3));
__ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
__ eor(r0, r0, Operand(1 << Map::kIsUndetectable));
__ mov(pc, Operand(lr)); // Return.
} }
...@@ -7445,9 +7465,10 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -7445,9 +7465,10 @@ void CompareStub::Generate(MacroAssembler* masm) {
// In the strict case the EmitStrictTwoHeapObjectCompare already took care of // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
// symbols. // symbols.
if (cc_ == eq && !strict_) { if (cc_ == eq && !strict_) {
// Either jumps to slow or returns the answer. Assumes that r2 is the type // Returns an answer for two symbols or two detectable objects.
// of r0 on entry. // Otherwise jumps to string case or not both strings case.
EmitCheckForSymbols(masm, &flat_string_check); // Assumes that r2 is the type of r0 on entry.
EmitCheckForSymbolsOrObjects(masm, &flat_string_check, &slow);
} }
// Check for both being sequential ASCII strings, and inline if that is the // Check for both being sequential ASCII strings, and inline if that is the
......
...@@ -11656,7 +11656,7 @@ static int NegativeComparisonResult(Condition cc) { ...@@ -11656,7 +11656,7 @@ static int NegativeComparisonResult(Condition cc) {
void CompareStub::Generate(MacroAssembler* masm) { 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 // 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. // it is certain that at least one operand isn't a smi.
...@@ -11734,79 +11734,75 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -11734,79 +11734,75 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ bind(&not_identical); __ bind(&not_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 slow; // Fallthrough label.
Label not_smis;
// If we're doing a strict equality comparison, we don't have to do // 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 // type conversion, so we generate code to do fast comparison for objects
// and oddballs. Non-smi numbers and strings still go through the usual // and oddballs. Non-smi numbers and strings still go through the usual
// slow-case code. // slow-case code.
if (strict_) { // If either is a Smi (we know that not both are), then they can only
// 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.
// be equal if the other is a HeapNumber. If so, use the slow case. ASSERT_EQ(0, kSmiTag);
{ ASSERT_EQ(0, Smi::FromInt(0));
Label not_smis; __ mov(ecx, Immediate(kSmiTagMask));
ASSERT_EQ(0, kSmiTag); __ and_(ecx, Operand(eax));
ASSERT_EQ(0, Smi::FromInt(0)); __ test(ecx, Operand(edx));
__ mov(ecx, Immediate(kSmiTagMask)); __ j(not_zero, &not_smis);
__ and_(ecx, Operand(eax)); // One operand is a smi.
__ test(ecx, Operand(edx));
__ j(not_zero, &not_smis); // Check whether the non-smi is a heap number.
// One operand is a smi. ASSERT_EQ(1, kSmiTagMask);
// ecx still holds eax & kSmiTag, which is either zero or one.
// Check whether the non-smi is a heap number. __ sub(Operand(ecx), Immediate(0x01));
ASSERT_EQ(1, kSmiTagMask); __ mov(ebx, edx);
// ecx still holds eax & kSmiTag, which is either zero or one. __ xor_(ebx, Operand(eax));
__ sub(Operand(ecx), Immediate(0x01)); __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx.
__ mov(ebx, edx); __ xor_(ebx, Operand(eax));
__ xor_(ebx, Operand(eax)); // if eax was smi, ebx is now edx, else eax.
__ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx.
__ xor_(ebx, Operand(eax)); // Check if the non-smi operand is a heap number.
// if eax was smi, ebx is now edx, else eax. __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
Immediate(Factory::heap_number_map()));
// Check if the non-smi operand is a heap number. // If heap number, handle it in the slow case.
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset), __ j(equal, &slow);
Immediate(Factory::heap_number_map())); // Return non-equal (ebx is not zero)
// If heap number, handle it in the slow case. __ mov(eax, ebx);
__ j(equal, &slow); __ ret(0);
// Return non-equal (ebx is not zero)
__ mov(eax, ebx);
__ ret(0);
__ bind(&not_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.
// 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) __ bind(&not_smis);
Label return_not_equal; // If either operand is a JSObject or an oddball value, then they are not
ASSERT(kHeapObjectTag != 0); // equal since their pointers are different
__ bind(&return_not_equal); // There is no test for undetectability in strict equality.
__ ret(0);
// 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);
__ bind(&first_non_object); __ bind(&first_non_object);
// Check for oddballs: true, false, null, undefined. // Check for oddballs: true, false, null, undefined.
__ CmpInstanceType(ecx, ODDBALL_TYPE); __ CmpInstanceType(ecx, ODDBALL_TYPE);
__ j(equal, &return_not_equal); __ j(equal, &return_not_equal);
__ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx);
__ j(above_equal, &return_not_equal); __ j(above_equal, &return_not_equal);
// Check for oddballs: true, false, null, undefined. // Check for oddballs: true, false, null, undefined.
__ CmpInstanceType(ecx, ODDBALL_TYPE); __ CmpInstanceType(ecx, ODDBALL_TYPE);
__ j(equal, &return_not_equal); __ j(equal, &return_not_equal);
// Fall through to the general case. // Fall through to the general case.
}
__ bind(&slow); __ bind(&slow);
} }
...@@ -11893,7 +11889,8 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -11893,7 +11889,8 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ bind(&check_for_strings); __ bind(&check_for_strings);
__ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &call_builtin); __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
&check_unequal_objects);
// Inline comparison of ascii strings. // Inline comparison of ascii strings.
StringCompareStub::GenerateCompareFlatAsciiStrings(masm, StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
...@@ -11906,7 +11903,44 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -11906,7 +11903,44 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ Abort("Unexpected fall-through from string comparison"); __ Abort("Unexpected fall-through from string comparison");
#endif #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, &not_both_objects);
__ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
__ j(below, &not_both_objects);
__ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ebx);
__ j(below, &not_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(&not_both_objects);
}
// must swap argument order // must swap argument order
__ pop(ecx); __ pop(ecx);
__ pop(edx); __ pop(edx);
......
...@@ -8938,7 +8938,7 @@ static int NegativeComparisonResult(Condition cc) { ...@@ -8938,7 +8938,7 @@ static int NegativeComparisonResult(Condition cc) {
void CompareStub::Generate(MacroAssembler* masm) { void CompareStub::Generate(MacroAssembler* masm) {
Label call_builtin, done; Label check_unequal_objects, done;
// The compare stub returns a positive, negative, or zero 64-bit integer // The compare stub returns a positive, negative, or zero 64-bit integer
// value in rax, corresponding to result of comparing the two inputs. // value in rax, corresponding to result of comparing the two inputs.
// NOTICE! This code is only reached after a smi-fast-case check, so // NOTICE! This code is only reached after a smi-fast-case check, so
...@@ -9113,7 +9113,7 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -9113,7 +9113,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ bind(&check_for_strings); __ bind(&check_for_strings);
__ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &call_builtin); __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &check_unequal_objects);
// Inline comparison of ascii strings. // Inline comparison of ascii strings.
StringCompareStub::GenerateCompareFlatAsciiStrings(masm, StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
...@@ -9128,7 +9128,40 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -9128,7 +9128,40 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ Abort("Unexpected fall-through from string comparison"); __ Abort("Unexpected fall-through from string comparison");
#endif #endif
__ bind(&call_builtin); __ bind(&check_unequal_objects);
if (cc_ == equal && !strict_) {
// Not strict equality. Objects are unequal if
// they are both JSObjects and not undetectable,
// and their pointers are different.
Label not_both_objects, 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(V8_UINT64_C(1), kSmiTagMask);
__ lea(rcx, Operand(rax, rdx, times_1, 0));
__ testb(rcx, Immediate(kSmiTagMask));
__ j(not_zero, &not_both_objects);
__ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
__ j(below, &not_both_objects);
__ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx);
__ j(below, &not_both_objects);
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(zero, &return_unequal);
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(zero, &return_unequal);
// The objects are both undetectable, so they both compare as the value
// undefined, and are equal.
__ Set(rax, 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(&not_both_objects);
}
// must swap argument order // must swap argument order
__ pop(rcx); __ pop(rcx);
__ pop(rdx); __ pop(rdx);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment