OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 11638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11649 | 11649 |
11650 static int NegativeComparisonResult(Condition cc) { | 11650 static int NegativeComparisonResult(Condition cc) { |
11651 ASSERT(cc != equal); | 11651 ASSERT(cc != equal); |
11652 ASSERT((cc == less) || (cc == less_equal) | 11652 ASSERT((cc == less) || (cc == less_equal) |
11653 || (cc == greater) || (cc == greater_equal)); | 11653 || (cc == greater) || (cc == greater_equal)); |
11654 return (cc == greater || cc == greater_equal) ? LESS : GREATER; | 11654 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
11655 } | 11655 } |
11656 | 11656 |
11657 | 11657 |
11658 void CompareStub::Generate(MacroAssembler* masm) { | 11658 void CompareStub::Generate(MacroAssembler* masm) { |
11659 Label call_builtin, done; | 11659 Label check_unequal_objects, done; |
11660 | 11660 |
11661 // NOTICE! This code is only reached after a smi-fast-case check, so | 11661 // NOTICE! This code is only reached after a smi-fast-case check, so |
11662 // it is certain that at least one operand isn't a smi. | 11662 // it is certain that at least one operand isn't a smi. |
11663 | 11663 |
11664 // Identical objects can be compared fast, but there are some tricky cases | 11664 // Identical objects can be compared fast, but there are some tricky cases |
11665 // for NaN and undefined. | 11665 // for NaN and undefined. |
11666 { | 11666 { |
11667 Label not_identical; | 11667 Label not_identical; |
11668 __ cmp(eax, Operand(edx)); | 11668 __ cmp(eax, Operand(edx)); |
11669 __ j(not_equal, ¬_identical); | 11669 __ j(not_equal, ¬_identical); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11727 __ ret(0); | 11727 __ ret(0); |
11728 __ bind(&nan); | 11728 __ bind(&nan); |
11729 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); | 11729 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); |
11730 __ ret(0); | 11730 __ ret(0); |
11731 } | 11731 } |
11732 } | 11732 } |
11733 | 11733 |
11734 __ bind(¬_identical); | 11734 __ bind(¬_identical); |
11735 } | 11735 } |
11736 | 11736 |
11737 if (cc_ == equal) { // Both strict and non-strict. | 11737 // Strict equality can quickly decide whether objects are equal. |
| 11738 // Non-strict object equality is slower, so it is handled later in the stub. |
| 11739 if (cc_ == equal && strict_) { |
11738 Label slow; // Fallthrough label. | 11740 Label slow; // Fallthrough label. |
11739 | 11741 Label not_smis; |
11740 // If we're doing a strict equality comparison, we don't have to do | 11742 // If we're doing a strict equality comparison, we don't have to do |
11741 // type conversion, so we generate code to do fast comparison for objects | 11743 // type conversion, so we generate code to do fast comparison for objects |
11742 // and oddballs. Non-smi numbers and strings still go through the usual | 11744 // and oddballs. Non-smi numbers and strings still go through the usual |
11743 // slow-case code. | 11745 // slow-case code. |
11744 if (strict_) { | 11746 // If either is a Smi (we know that not both are), then they can only |
11745 // If either is a Smi (we know that not both are), then they can only | 11747 // be equal if the other is a HeapNumber. If so, use the slow case. |
11746 // be equal if the other is a HeapNumber. If so, use the slow case. | 11748 ASSERT_EQ(0, kSmiTag); |
11747 { | 11749 ASSERT_EQ(0, Smi::FromInt(0)); |
11748 Label not_smis; | 11750 __ mov(ecx, Immediate(kSmiTagMask)); |
11749 ASSERT_EQ(0, kSmiTag); | 11751 __ and_(ecx, Operand(eax)); |
11750 ASSERT_EQ(0, Smi::FromInt(0)); | 11752 __ test(ecx, Operand(edx)); |
11751 __ mov(ecx, Immediate(kSmiTagMask)); | 11753 __ j(not_zero, ¬_smis); |
11752 __ and_(ecx, Operand(eax)); | 11754 // One operand is a smi. |
11753 __ test(ecx, Operand(edx)); | |
11754 __ j(not_zero, ¬_smis); | |
11755 // One operand is a smi. | |
11756 | 11755 |
11757 // Check whether the non-smi is a heap number. | 11756 // Check whether the non-smi is a heap number. |
11758 ASSERT_EQ(1, kSmiTagMask); | 11757 ASSERT_EQ(1, kSmiTagMask); |
11759 // ecx still holds eax & kSmiTag, which is either zero or one. | 11758 // ecx still holds eax & kSmiTag, which is either zero or one. |
11760 __ sub(Operand(ecx), Immediate(0x01)); | 11759 __ sub(Operand(ecx), Immediate(0x01)); |
11761 __ mov(ebx, edx); | 11760 __ mov(ebx, edx); |
11762 __ xor_(ebx, Operand(eax)); | 11761 __ xor_(ebx, Operand(eax)); |
11763 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. | 11762 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. |
11764 __ xor_(ebx, Operand(eax)); | 11763 __ xor_(ebx, Operand(eax)); |
11765 // if eax was smi, ebx is now edx, else eax. | 11764 // if eax was smi, ebx is now edx, else eax. |
11766 | 11765 |
11767 // Check if the non-smi operand is a heap number. | 11766 // Check if the non-smi operand is a heap number. |
11768 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 11767 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
11769 Immediate(Factory::heap_number_map())); | 11768 Immediate(Factory::heap_number_map())); |
11770 // If heap number, handle it in the slow case. | 11769 // If heap number, handle it in the slow case. |
11771 __ j(equal, &slow); | 11770 __ j(equal, &slow); |
11772 // Return non-equal (ebx is not zero) | 11771 // Return non-equal (ebx is not zero) |
11773 __ mov(eax, ebx); | 11772 __ mov(eax, ebx); |
11774 __ ret(0); | 11773 __ ret(0); |
11775 | 11774 |
11776 __ bind(¬_smis); | 11775 __ bind(¬_smis); |
11777 } | 11776 // If either operand is a JSObject or an oddball value, then they are not |
| 11777 // equal since their pointers are different |
| 11778 // There is no test for undetectability in strict equality. |
11778 | 11779 |
11779 // If either operand is a JSObject or an oddball value, then they are not | 11780 // Get the type of the first operand. |
11780 // equal since their pointers are different | 11781 // If the first object is a JS object, we have done pointer comparison. |
11781 // There is no test for undetectability in strict equality. | 11782 Label first_non_object; |
| 11783 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 11784 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 11785 __ j(below, &first_non_object); |
11782 | 11786 |
11783 // Get the type of the first operand. | 11787 // Return non-zero (eax is not zero) |
11784 // If the first object is a JS object, we have done pointer comparison. | 11788 Label return_not_equal; |
11785 Label first_non_object; | 11789 ASSERT(kHeapObjectTag != 0); |
11786 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 11790 __ bind(&return_not_equal); |
11787 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 11791 __ ret(0); |
11788 __ j(below, &first_non_object); | |
11789 | 11792 |
11790 // Return non-zero (eax is not zero) | 11793 __ bind(&first_non_object); |
11791 Label return_not_equal; | 11794 // Check for oddballs: true, false, null, undefined. |
11792 ASSERT(kHeapObjectTag != 0); | 11795 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
11793 __ bind(&return_not_equal); | 11796 __ j(equal, &return_not_equal); |
11794 __ ret(0); | |
11795 | 11797 |
11796 __ bind(&first_non_object); | 11798 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); |
11797 // Check for oddballs: true, false, null, undefined. | 11799 __ j(above_equal, &return_not_equal); |
11798 __ CmpInstanceType(ecx, ODDBALL_TYPE); | |
11799 __ j(equal, &return_not_equal); | |
11800 | 11800 |
11801 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); | 11801 // Check for oddballs: true, false, null, undefined. |
11802 __ j(above_equal, &return_not_equal); | 11802 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
| 11803 __ j(equal, &return_not_equal); |
11803 | 11804 |
11804 // Check for oddballs: true, false, null, undefined. | 11805 // Fall through to the general case. |
11805 __ CmpInstanceType(ecx, ODDBALL_TYPE); | |
11806 __ j(equal, &return_not_equal); | |
11807 | |
11808 // Fall through to the general case. | |
11809 } | |
11810 __ bind(&slow); | 11806 __ bind(&slow); |
11811 } | 11807 } |
11812 | 11808 |
11813 // Push arguments below the return address. | 11809 // Push arguments below the return address. |
11814 __ pop(ecx); | 11810 __ pop(ecx); |
11815 __ push(eax); | 11811 __ push(eax); |
11816 __ push(edx); | 11812 __ push(edx); |
11817 __ push(ecx); | 11813 __ push(ecx); |
11818 | 11814 |
11819 // Generate the number comparison code. | 11815 // Generate the number comparison code. |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11886 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); | 11882 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); |
11887 | 11883 |
11888 // We've already checked for object identity, so if both operands | 11884 // We've already checked for object identity, so if both operands |
11889 // are symbols they aren't equal. Register eax already holds a | 11885 // are symbols they aren't equal. Register eax already holds a |
11890 // non-zero value, which indicates not equal, so just return. | 11886 // non-zero value, which indicates not equal, so just return. |
11891 __ ret(2 * kPointerSize); | 11887 __ ret(2 * kPointerSize); |
11892 } | 11888 } |
11893 | 11889 |
11894 __ bind(&check_for_strings); | 11890 __ bind(&check_for_strings); |
11895 | 11891 |
11896 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &call_builtin); | 11892 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, |
| 11893 &check_unequal_objects); |
11897 | 11894 |
11898 // Inline comparison of ascii strings. | 11895 // Inline comparison of ascii strings. |
11899 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, | 11896 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
11900 edx, | 11897 edx, |
11901 eax, | 11898 eax, |
11902 ecx, | 11899 ecx, |
11903 ebx, | 11900 ebx, |
11904 edi); | 11901 edi); |
11905 #ifdef DEBUG | 11902 #ifdef DEBUG |
11906 __ Abort("Unexpected fall-through from string comparison"); | 11903 __ Abort("Unexpected fall-through from string comparison"); |
11907 #endif | 11904 #endif |
11908 | 11905 |
11909 __ bind(&call_builtin); | 11906 __ bind(&check_unequal_objects); |
| 11907 if (cc_ == equal && !strict_) { |
| 11908 // Non-strict equality. Objects are unequal if |
| 11909 // they are both JSObjects and not undetectable, |
| 11910 // and their pointers are different. |
| 11911 Label not_both_objects; |
| 11912 Label return_unequal; |
| 11913 // At most one is a smi, so we can test for smi by adding the two. |
| 11914 // A smi plus a heap object has the low bit set, a heap object plus |
| 11915 // a heap object has the low bit clear. |
| 11916 ASSERT_EQ(0, kSmiTag); |
| 11917 ASSERT_EQ(1, kSmiTagMask); |
| 11918 __ lea(ecx, Operand(eax, edx, times_1, 0)); |
| 11919 __ test(ecx, Immediate(kSmiTagMask)); |
| 11920 __ j(not_zero, ¬_both_objects); |
| 11921 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 11922 __ j(below, ¬_both_objects); |
| 11923 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ebx); |
| 11924 __ j(below, ¬_both_objects); |
| 11925 // We do not bail out after this point. Both are JSObjects, and |
| 11926 // they are equal if and only if both are undetectable. |
| 11927 // The and of the undetectable flags is 1 if and only if they are equal. |
| 11928 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), |
| 11929 1 << Map::kIsUndetectable); |
| 11930 __ j(zero, &return_unequal); |
| 11931 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), |
| 11932 1 << Map::kIsUndetectable); |
| 11933 __ j(zero, &return_unequal); |
| 11934 // The objects are both undetectable, so they both compare as the value |
| 11935 // undefined, and are equal. |
| 11936 __ Set(eax, Immediate(EQUAL)); |
| 11937 __ bind(&return_unequal); |
| 11938 // Return non-equal by returning the non-zero object pointer in eax, |
| 11939 // or return equal if we fell through to here. |
| 11940 __ ret(2 * kPointerSize); // rax, rdx were pushed |
| 11941 __ bind(¬_both_objects); |
| 11942 } |
| 11943 |
11910 // must swap argument order | 11944 // must swap argument order |
11911 __ pop(ecx); | 11945 __ pop(ecx); |
11912 __ pop(edx); | 11946 __ pop(edx); |
11913 __ pop(eax); | 11947 __ pop(eax); |
11914 __ push(edx); | 11948 __ push(edx); |
11915 __ push(eax); | 11949 __ push(eax); |
11916 | 11950 |
11917 // Figure out which native to call and setup the arguments. | 11951 // Figure out which native to call and setup the arguments. |
11918 Builtins::JavaScript builtin; | 11952 Builtins::JavaScript builtin; |
11919 if (cc_ == equal) { | 11953 if (cc_ == equal) { |
(...skipping 1816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13736 masm.GetCode(&desc); | 13770 masm.GetCode(&desc); |
13737 // Call the function from C++. | 13771 // Call the function from C++. |
13738 return FUNCTION_CAST<MemCopyFunction>(buffer); | 13772 return FUNCTION_CAST<MemCopyFunction>(buffer); |
13739 } | 13773 } |
13740 | 13774 |
13741 #undef __ | 13775 #undef __ |
13742 | 13776 |
13743 } } // namespace v8::internal | 13777 } } // namespace v8::internal |
13744 | 13778 |
13745 #endif // V8_TARGET_ARCH_IA32 | 13779 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |