Commit 5dc51480 authored by lrn@chromium.org's avatar lrn@chromium.org

Quick pointer comparison, removed undetectable tests.

Special case for NaN in equality test.


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1676 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 3e55df5a
...@@ -6541,69 +6541,130 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { ...@@ -6541,69 +6541,130 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
void CompareStub::Generate(MacroAssembler* masm) { void CompareStub::Generate(MacroAssembler* masm) {
Label call_builtin, done; Label call_builtin, done;
// If we're doing a strict equality comparison, we generate code // NOTICE! This code is only reached after a smi-fast-case check, so
// to do fast comparison for objects and oddballs. Numbers and // it is certain that at least one operand isn't a smi.
// strings still go through the usual slow-case code.
if (cc_ == equal) { // Both strict and non-strict.
Label slow; // Fallthrough label.
// Equality is almost reflexive (everything but NaN), so start by testing
// for "identity and not NaN".
{
Label not_identical;
__ cmp(eax, Operand(edx));
__ j(not_equal, &not_identical);
// Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
// so we do the second best thing - test it ourselves.
Label return_equal;
Label heap_number;
// If it's not a heap number, then return equal.
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Factory::heap_number_map()));
__ j(equal, &heap_number);
__ bind(&return_equal);
__ Set(eax, Immediate(0));
__ ret(0);
__ 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).
__ mov(eax, FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize));
// Test that exponent bits are all set.
__ not_(eax);
__ test(eax, Immediate(0x7ff00000));
__ j(not_zero, &return_equal);
__ not_(eax);
// Shift out flag and all exponent bits, retaining only mantissa.
__ shl(eax, 12);
// Or with all low-bits of mantissa.
__ or_(eax, FieldOperand(edx, HeapNumber::kValueOffset));
// Return zero equal if all bits in mantissa is zero (it's an Infinity)
// and non-zero if not (it's a NaN).
__ ret(0);
__ bind(&not_identical);
}
// 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 (strict_) {
Label slow; // If either is a Smi (we know that not both are), then they can only
__ test(eax, Immediate(kSmiTagMask)); // be equal if the other is a HeapNumber. If so, use the slow case.
__ j(zero, &slow); {
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, &not_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 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(&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. // Get the type of the first operand.
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
// If the first object is an object, we do pointer comparison. // If the first object is a JS object, we have done pointer comparison.
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
Label non_object; Label first_non_object;
__ cmp(ecx, FIRST_JS_OBJECT_TYPE); __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(less, &non_object); __ j(less, &first_non_object);
__ sub(eax, Operand(edx));
// Return non-zero (eax is not zero)
Label return_not_equal;
ASSERT(kHeapObjectTag != 0);
__ bind(&return_not_equal);
__ ret(0); __ ret(0);
__ bind(&first_non_object);
// Check for oddballs: true, false, null, undefined. // Check for oddballs: true, false, null, undefined.
__ bind(&non_object);
__ cmp(ecx, ODDBALL_TYPE); __ cmp(ecx, ODDBALL_TYPE);
__ j(not_equal, &slow); __ j(equal, &return_not_equal);
// If the oddball isn't undefined, we do pointer comparison. For
// the undefined value, we have to be careful and check for
// 'undetectable' objects too.
Label undefined;
__ cmp(Operand(eax), Immediate(Factory::undefined_value()));
__ j(equal, &undefined);
__ sub(eax, Operand(edx));
__ ret(0);
// Undefined case: If the other operand isn't undefined too, we
// have to check if it's 'undetectable'.
Label check_undetectable;
__ bind(&undefined);
__ cmp(Operand(edx), Immediate(Factory::undefined_value()));
__ j(not_equal, &check_undetectable);
__ Set(eax, Immediate(0));
__ ret(0);
// Check for undetectability of the other operand.
Label not_strictly_equal;
__ bind(&check_undetectable);
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &not_strictly_equal);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ and_(ecx, 1 << Map::kIsUndetectable);
__ cmp(ecx, 1 << Map::kIsUndetectable);
__ j(not_equal, &not_strictly_equal);
__ Set(eax, Immediate(0));
__ ret(0);
// No cigar: Objects aren't strictly equal. Register eax contains __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
// a non-smi value so it can't be 0. Just return. __ j(greater_equal, &return_not_equal);
ASSERT(kHeapObjectTag != 0);
__ bind(&not_strictly_equal); // Check for oddballs: true, false, null, undefined.
__ ret(0); __ cmp(ecx, ODDBALL_TYPE);
__ j(equal, &return_not_equal);
// Fall through to the general case. // Fall through to the general case.
}
__ bind(&slow); __ bind(&slow);
} }
......
...@@ -104,13 +104,9 @@ function STRICT_EQUALS(x) { ...@@ -104,13 +104,9 @@ function STRICT_EQUALS(x) {
return %NumberEquals(this, x); return %NumberEquals(this, x);
} }
if (IS_UNDEFINED(this)) { // If anything else gets here, we just do simple identity check.
// Both undefined and undetectable. // Objects (including functions), null, undefined and booleans were
return IS_UNDEFINED(x) ? 0 : 1; // checked in the CompareStub, so there should be nothing left.
}
// Objects, null, booleans and functions are all that's left.
// They can all be compared with a simple identity check.
return %_ObjectEquals(this, x) ? 0 : 1; return %_ObjectEquals(this, x) ? 0 : 1;
} }
......
...@@ -2383,11 +2383,16 @@ THREADED_TEST(UndetectableObject) { ...@@ -2383,11 +2383,16 @@ THREADED_TEST(UndetectableObject) {
ExpectBoolean("undetectable||false", false); ExpectBoolean("undetectable||false", false);
ExpectBoolean("undetectable==null", true); ExpectBoolean("undetectable==null", true);
ExpectBoolean("null==undetectable", true);
ExpectBoolean("undetectable==undefined", true); ExpectBoolean("undetectable==undefined", true);
ExpectBoolean("undefined==undetectable", true);
ExpectBoolean("undetectable==undetectable", true); ExpectBoolean("undetectable==undetectable", true);
ExpectBoolean("undetectable===null", false); ExpectBoolean("undetectable===null", false);
ExpectBoolean("undetectable===undefined", true); ExpectBoolean("null===undetectable", false);
ExpectBoolean("undetectable===undefined", false);
ExpectBoolean("undefined===undetectable", false);
ExpectBoolean("undetectable===undetectable", true); ExpectBoolean("undetectable===undetectable", true);
} }
...@@ -2418,11 +2423,16 @@ THREADED_TEST(UndetectableString) { ...@@ -2418,11 +2423,16 @@ THREADED_TEST(UndetectableString) {
ExpectBoolean("undetectable||false", false); ExpectBoolean("undetectable||false", false);
ExpectBoolean("undetectable==null", true); ExpectBoolean("undetectable==null", true);
ExpectBoolean("null==undetectable", true);
ExpectBoolean("undetectable==undefined", true); ExpectBoolean("undetectable==undefined", true);
ExpectBoolean("undefined==undetectable", true);
ExpectBoolean("undetectable==undetectable", true); ExpectBoolean("undetectable==undetectable", true);
ExpectBoolean("undetectable===null", false); ExpectBoolean("undetectable===null", false);
ExpectBoolean("undetectable===undefined", true); ExpectBoolean("null===undetectable", false);
ExpectBoolean("undetectable===undefined", false);
ExpectBoolean("undefined===undetectable", false);
ExpectBoolean("undetectable===undetectable", true); ExpectBoolean("undetectable===undetectable", true);
} }
......
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