OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 8557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8568 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); | 8568 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); |
8569 | 8569 |
8570 // We've already checked for object identity, so if both operands | 8570 // We've already checked for object identity, so if both operands |
8571 // are symbols they aren't equal. Register eax already holds a | 8571 // are symbols they aren't equal. Register eax already holds a |
8572 // non-zero value, which indicates not equal, so just return. | 8572 // non-zero value, which indicates not equal, so just return. |
8573 __ ret(2 * kPointerSize); | 8573 __ ret(2 * kPointerSize); |
8574 } | 8574 } |
8575 | 8575 |
8576 __ bind(&check_for_strings); | 8576 __ bind(&check_for_strings); |
8577 | 8577 |
8578 // Check that both objects are not smis. | 8578 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &call_builtin); |
8579 ASSERT_EQ(0, kSmiTag); | |
8580 __ mov(ebx, Operand(edx)); | |
8581 __ and_(ebx, Operand(eax)); | |
8582 __ test(ebx, Immediate(kSmiTagMask)); | |
8583 __ j(zero, &call_builtin); | |
8584 | |
8585 // Load instance type for both objects. | |
8586 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
8587 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | |
8588 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
8589 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
8590 | |
8591 // Check that both are flat ascii strings. | |
8592 Label non_ascii_flat; | |
8593 ASSERT(kNotStringTag != 0); | |
8594 const int kFlatAsciiString = | |
8595 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; | |
8596 __ and_(ecx, kFlatAsciiString); | |
8597 __ cmp(ecx, kStringTag | kSeqStringTag | kAsciiStringTag); | |
8598 __ j(not_equal, &call_builtin); | |
8599 __ and_(ebx, kFlatAsciiString); | |
8600 __ cmp(ebx, kStringTag | kSeqStringTag | kAsciiStringTag); | |
8601 __ j(not_equal, &call_builtin); | |
8602 | 8579 |
8603 // Inline comparison of ascii strings. | 8580 // Inline comparison of ascii strings. |
8604 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, | 8581 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
8605 edx, | 8582 edx, |
8606 eax, | 8583 eax, |
8607 ecx, | 8584 ecx, |
8608 ebx, | 8585 ebx, |
8609 edi); | 8586 edi); |
8610 #ifdef DEBUG | 8587 #ifdef DEBUG |
8611 __ Abort("Unexpected fall-through from string comparison"); | 8588 __ Abort("Unexpected fall-through from string comparison"); |
(...skipping 1033 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9645 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); | 9622 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); |
9646 } | 9623 } |
9647 | 9624 |
9648 | 9625 |
9649 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 9626 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
9650 Register left, | 9627 Register left, |
9651 Register right, | 9628 Register right, |
9652 Register scratch1, | 9629 Register scratch1, |
9653 Register scratch2, | 9630 Register scratch2, |
9654 Register scratch3) { | 9631 Register scratch3) { |
9655 Label compare_lengths, compare_lengths_1; | 9632 Label result_not_equal; |
| 9633 Label result_greater; |
| 9634 Label compare_lengths; |
| 9635 // Find minimum length. |
| 9636 Label left_shorter; |
| 9637 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
| 9638 __ mov(scratch3, scratch1); |
| 9639 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |
9656 | 9640 |
9657 // Find minimum length. If either length is zero just compare lengths. | 9641 Register length_delta = scratch3; |
9658 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 9642 |
9659 __ test(scratch1, Operand(scratch1)); | 9643 __ j(less_equal, &left_shorter); |
9660 __ j(zero, &compare_lengths_1); | 9644 // Right string is shorter. Change scratch1 to be length of right string. |
9661 __ mov(scratch2, FieldOperand(right, String::kLengthOffset)); | 9645 __ sub(scratch1, Operand(length_delta)); |
9662 __ test(scratch2, Operand(scratch2)); | 9646 __ bind(&left_shorter); |
9663 __ j(zero, &compare_lengths_1); | 9647 |
9664 __ cmp(scratch1, Operand(scratch2)); | 9648 Register min_length = scratch1; |
9665 if (CpuFeatures::IsSupported(CMOV)) { | 9649 |
9666 CpuFeatures::Scope use_cmov(CMOV); | 9650 // If either length is zero, just compare lengths. |
9667 __ cmov(greater, scratch1, Operand(scratch2)); | 9651 __ test(min_length, Operand(min_length)); |
9668 } else { | 9652 __ j(zero, &compare_lengths); |
9669 Label l; | 9653 |
9670 __ j(less, &l); | 9654 // Change index to run from -min_length to -1 by adding min_length |
9671 __ mov(scratch1, scratch2); | 9655 // to string start. This means that loop ends when index reaches zero, |
9672 __ bind(&l); | 9656 // which doesn't need an additional compare. |
| 9657 __ lea(left, |
| 9658 FieldOperand(left, |
| 9659 min_length, times_1, |
| 9660 SeqAsciiString::kHeaderSize)); |
| 9661 __ lea(right, |
| 9662 FieldOperand(right, |
| 9663 min_length, times_1, |
| 9664 SeqAsciiString::kHeaderSize)); |
| 9665 __ neg(min_length); |
| 9666 |
| 9667 Register index = min_length; // index = -min_length; |
| 9668 |
| 9669 { |
| 9670 // Compare loop. |
| 9671 Label loop; |
| 9672 __ bind(&loop); |
| 9673 // Compare characters. |
| 9674 __ mov_b(scratch2, Operand(left, index, times_1, 0)); |
| 9675 __ cmpb(scratch2, Operand(right, index, times_1, 0)); |
| 9676 __ j(not_equal, &result_not_equal); |
| 9677 __ add(Operand(index), Immediate(1)); |
| 9678 __ j(not_zero, &loop); |
9673 } | 9679 } |
9674 | 9680 |
9675 Label result_greater, result_less; | 9681 // Compare lengths - strings up to min-length are equal. |
9676 Label loop; | |
9677 // Compare next character. | |
9678 __ mov(scratch3, Immediate(-1)); // Index into strings. | |
9679 __ bind(&loop); | |
9680 // Compare characters. | |
9681 Label character_compare_done; | |
9682 __ add(Operand(scratch3), Immediate(1)); | |
9683 __ mov_b(scratch2, Operand(left, | |
9684 scratch3, | |
9685 times_1, | |
9686 SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
9687 __ subb(scratch2, Operand(right, | |
9688 scratch3, | |
9689 times_1, | |
9690 SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
9691 __ j(not_equal, &character_compare_done); | |
9692 __ sub(Operand(scratch1), Immediate(1)); | |
9693 __ j(not_zero, &loop); | |
9694 // If min length characters match compare lengths otherwise last character | |
9695 // compare is the result. | |
9696 __ bind(&character_compare_done); | |
9697 __ j(equal, &compare_lengths); | |
9698 __ j(less, &result_less); | |
9699 __ jmp(&result_greater); | |
9700 | |
9701 // Compare lengths. | |
9702 Label result_not_equal; | |
9703 __ bind(&compare_lengths); | 9682 __ bind(&compare_lengths); |
9704 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 9683 __ test(length_delta, Operand(length_delta)); |
9705 __ bind(&compare_lengths_1); | |
9706 __ sub(scratch1, FieldOperand(right, String::kLengthOffset)); | |
9707 __ j(not_zero, &result_not_equal); | 9684 __ j(not_zero, &result_not_equal); |
9708 | 9685 |
9709 // Result is EQUAL. | 9686 // Result is EQUAL. |
9710 ASSERT_EQ(0, EQUAL); | 9687 ASSERT_EQ(0, EQUAL); |
9711 ASSERT_EQ(0, kSmiTag); | 9688 ASSERT_EQ(0, kSmiTag); |
9712 __ xor_(eax, Operand(eax)); | 9689 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
9713 __ IncrementCounter(&Counters::string_compare_native, 1); | |
9714 __ ret(2 * kPointerSize); | 9690 __ ret(2 * kPointerSize); |
| 9691 |
9715 __ bind(&result_not_equal); | 9692 __ bind(&result_not_equal); |
9716 __ j(greater, &result_greater); | 9693 __ j(greater, &result_greater); |
9717 | 9694 |
9718 // Result is LESS. | 9695 // Result is LESS. |
9719 __ bind(&result_less); | 9696 __ Set(eax, Immediate(Smi::FromInt(LESS))); |
9720 __ mov(eax, Immediate(Smi::FromInt(LESS)->value())); | |
9721 __ IncrementCounter(&Counters::string_compare_native, 1); | |
9722 __ ret(2 * kPointerSize); | 9697 __ ret(2 * kPointerSize); |
9723 | 9698 |
9724 // Result is GREATER. | 9699 // Result is GREATER. |
9725 __ bind(&result_greater); | 9700 __ bind(&result_greater); |
9726 __ mov(eax, Immediate(Smi::FromInt(GREATER)->value())); | 9701 __ Set(eax, Immediate(Smi::FromInt(GREATER))); |
9727 __ IncrementCounter(&Counters::string_compare_native, 1); | |
9728 __ ret(2 * kPointerSize); | 9702 __ ret(2 * kPointerSize); |
9729 } | 9703 } |
9730 | 9704 |
9731 | 9705 |
9732 void StringCompareStub::Generate(MacroAssembler* masm) { | 9706 void StringCompareStub::Generate(MacroAssembler* masm) { |
9733 Label runtime; | 9707 Label runtime; |
9734 | 9708 |
9735 // Stack frame on entry. | 9709 // Stack frame on entry. |
9736 // esp[0]: return address | 9710 // esp[0]: return address |
9737 // esp[4]: right string | 9711 // esp[4]: right string |
9738 // esp[8]: left string | 9712 // esp[8]: left string |
9739 | 9713 |
9740 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left | 9714 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left |
9741 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right | 9715 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right |
9742 | 9716 |
9743 Label not_same; | 9717 Label not_same; |
9744 __ cmp(edx, Operand(eax)); | 9718 __ cmp(edx, Operand(eax)); |
9745 __ j(not_equal, ¬_same); | 9719 __ j(not_equal, ¬_same); |
9746 ASSERT_EQ(0, EQUAL); | 9720 ASSERT_EQ(0, EQUAL); |
9747 ASSERT_EQ(0, kSmiTag); | 9721 ASSERT_EQ(0, kSmiTag); |
9748 __ xor_(eax, Operand(eax)); | 9722 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
9749 __ IncrementCounter(&Counters::string_compare_native, 1); | 9723 __ IncrementCounter(&Counters::string_compare_native, 1); |
9750 __ ret(2 * kPointerSize); | 9724 __ ret(2 * kPointerSize); |
9751 | 9725 |
9752 __ bind(¬_same); | 9726 __ bind(¬_same); |
9753 | 9727 |
9754 // Check that both objects are not smis. | 9728 // Check that both objects are sequential ascii strings. |
9755 ASSERT_EQ(0, kSmiTag); | 9729 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
9756 __ mov(ebx, Operand(edx)); | |
9757 __ and_(ebx, Operand(eax)); | |
9758 __ test(ebx, Immediate(kSmiTagMask)); | |
9759 __ j(zero, &runtime); | |
9760 | |
9761 // Load instance type for both strings. | |
9762 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
9763 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | |
9764 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
9765 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
9766 | |
9767 // Check that both are flat ascii strings. | |
9768 Label non_ascii_flat; | |
9769 __ and_(ecx, kStringRepresentationMask | kStringEncodingMask); | |
9770 __ cmp(ecx, kSeqStringTag | kAsciiStringTag); | |
9771 __ j(not_equal, &non_ascii_flat); | |
9772 const int kFlatAsciiString = | |
9773 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; | |
9774 __ and_(ebx, kFlatAsciiString); | |
9775 __ cmp(ebx, kStringTag | kSeqStringTag | kAsciiStringTag); | |
9776 __ j(not_equal, &non_ascii_flat); | |
9777 | 9730 |
9778 // Compare flat ascii strings. | 9731 // Compare flat ascii strings. |
| 9732 __ IncrementCounter(&Counters::string_compare_native, 1); |
9779 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 9733 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
9780 | 9734 |
9781 __ bind(&non_ascii_flat); | |
9782 | |
9783 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 9735 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
9784 // tagged as a small integer. | 9736 // tagged as a small integer. |
9785 __ bind(&runtime); | 9737 __ bind(&runtime); |
9786 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 9738 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
9787 } | 9739 } |
9788 | 9740 |
9789 #undef __ | 9741 #undef __ |
9790 | 9742 |
9791 } } // namespace v8::internal | 9743 } } // namespace v8::internal |
OLD | NEW |