| 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 |