Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Unified Diff: src/codegen-ia32.cc

Issue 60085: Rewrote equality check in CompareStub to do quick pointer comparison first. (Closed)
Patch Set: Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/cctest/test-api.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codegen-ia32.cc
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index 0e2a370017b30ce259e6560583dd889ef5f447cd..27faaf93e13b5daa608b2c28487fc7095b73168c 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -6513,69 +6513,130 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
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, &not_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, &not_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(&not_strictly_equal);
- __ ret(0);
-
- // Fall through to the general case.
+ // 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.
+
+ 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);
+
+ // Try to read the first word of the heap-number. This is the high
Erik Corry 2009/04/03 12:31:56 Comment looks wrong.
+ // bits of the double number, and contains the exponent.
+ __ bind(&heap_number);
+ // If it is a heap number, then check if it's NaN, and return not-equal
+ // 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 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, &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.
+ __ 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);
}
« no previous file with comments | « no previous file | test/cctest/test-api.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698