Author: [email protected]
Date: Fri Apr 3 05:44:45 2009
New Revision: 1676
Modified:
branches/bleeding_edge/src/codegen-ia32.cc
branches/bleeding_edge/src/runtime.js
branches/bleeding_edge/test/cctest/test-api.cc
Log:
Quick pointer comparison, removed undetectable tests.
Special case for NaN in equality test.
Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc Fri Apr 3 05:44:45 2009
@@ -6541,69 +6541,130 @@
void CompareStub::Generate(MacroAssembler* masm) {
Label call_builtin, done;
- // If we're doing a strict equality comparison, we generate code
- // to do fast comparison for objects and oddballs. Numbers and
- // strings still go through the usual slow-case code.
- if (strict_) {
- Label slow;
- __ test(eax, Immediate(kSmiTagMask));
- __ j(zero, &slow);
-
- // Get the type of the first operand.
- __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
- __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
-
- // If the first object is an object, we do pointer comparison.
- ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
- Label non_object;
- __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
- __ j(less, &non_object);
- __ sub(eax, Operand(edx));
- __ ret(0);
-
- // Check for oddballs: true, false, null, undefined.
- __ bind(&non_object);
- __ cmp(ecx, ODDBALL_TYPE);
- __ j(not_equal, &slow);
-
- // 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, ¬_strictly_equal);
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
- __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
- __ and_(ecx, 1 << Map::kIsUndetectable);
- __ cmp(ecx, 1 << Map::kIsUndetectable);
- __ j(not_equal, ¬_strictly_equal);
- __ Set(eax, Immediate(0));
- __ ret(0);
-
- // No cigar: Objects aren't strictly equal. Register eax contains
- // a non-smi value so it can't be 0. Just return.
- ASSERT(kHeapObjectTag != 0);
- __ bind(¬_strictly_equal);
- __ ret(0);
+ // 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.
- // Fall through to the general case.
+ 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, ¬_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(¬_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 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.
+
+ // 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(¬_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.
+ __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
+ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+
+ // If the first object is a JS object, we have done pointer
comparison.
+ ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+ Label first_non_object;
+ __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+ __ j(less, &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);
+ // Check for oddballs: true, false, null, undefined.
+ __ cmp(ecx, ODDBALL_TYPE);
+ __ j(equal, &return_not_equal);
+
+ __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+
+ __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+ __ j(greater_equal, &return_not_equal);
+
+ // Check for oddballs: true, false, null, undefined.
+ __ cmp(ecx, ODDBALL_TYPE);
+ __ j(equal, &return_not_equal);
+
+ // Fall through to the general case.
+ }
__ bind(&slow);
}
Modified: branches/bleeding_edge/src/runtime.js
==============================================================================
--- branches/bleeding_edge/src/runtime.js (original)
+++ branches/bleeding_edge/src/runtime.js Fri Apr 3 05:44:45 2009
@@ -104,13 +104,9 @@
return %NumberEquals(this, x);
}
- if (IS_UNDEFINED(this)) {
- // Both undefined and undetectable.
- return IS_UNDEFINED(x) ? 0 : 1;
- }
-
- // Objects, null, booleans and functions are all that's left.
- // They can all be compared with a simple identity check.
+ // If anything else gets here, we just do simple identity check.
+ // Objects (including functions), null, undefined and booleans were
+ // checked in the CompareStub, so there should be nothing left.
return %_ObjectEquals(this, x) ? 0 : 1;
}
Modified: branches/bleeding_edge/test/cctest/test-api.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-api.cc (original)
+++ branches/bleeding_edge/test/cctest/test-api.cc Fri Apr 3 05:44:45 2009
@@ -2383,11 +2383,16 @@
ExpectBoolean("undetectable||false", false);
ExpectBoolean("undetectable==null", true);
+ ExpectBoolean("null==undetectable", true);
ExpectBoolean("undetectable==undefined", true);
+ ExpectBoolean("undefined==undetectable", true);
ExpectBoolean("undetectable==undetectable", true);
+
ExpectBoolean("undetectable===null", false);
- ExpectBoolean("undetectable===undefined", true);
+ ExpectBoolean("null===undetectable", false);
+ ExpectBoolean("undetectable===undefined", false);
+ ExpectBoolean("undefined===undetectable", false);
ExpectBoolean("undetectable===undetectable", true);
}
@@ -2418,11 +2423,16 @@
ExpectBoolean("undetectable||false", false);
ExpectBoolean("undetectable==null", true);
+ ExpectBoolean("null==undetectable", true);
ExpectBoolean("undetectable==undefined", true);
+ ExpectBoolean("undefined==undetectable", true);
ExpectBoolean("undetectable==undetectable", true);
+
ExpectBoolean("undetectable===null", false);
- ExpectBoolean("undetectable===undefined", true);
+ ExpectBoolean("null===undetectable", false);
+ ExpectBoolean("undetectable===undefined", false);
+ ExpectBoolean("undefined===undetectable", false);
ExpectBoolean("undetectable===undetectable", true);
}
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---