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 3558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3569 frame_->EmitPush(r0); | 3569 frame_->EmitPush(r0); |
3570 } | 3570 } |
3571 | 3571 |
3572 | 3572 |
3573 void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) { | 3573 void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) { |
3574 ASSERT_EQ(2, args->length()); | 3574 ASSERT_EQ(2, args->length()); |
3575 | 3575 |
3576 Load(args->at(0)); | 3576 Load(args->at(0)); |
3577 Load(args->at(1)); | 3577 Load(args->at(1)); |
3578 | 3578 |
3579 frame_->CallRuntime(Runtime::kStringCompare, 2); | 3579 StringCompareStub stub; |
| 3580 frame_->CallStub(&stub, 2); |
3580 frame_->EmitPush(r0); | 3581 frame_->EmitPush(r0); |
3581 } | 3582 } |
3582 | 3583 |
3583 | 3584 |
3584 void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { | 3585 void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { |
3585 ASSERT_EQ(4, args->length()); | 3586 ASSERT_EQ(4, args->length()); |
3586 | 3587 |
3587 Load(args->at(0)); | 3588 Load(args->at(0)); |
3588 Load(args->at(1)); | 3589 Load(args->at(1)); |
3589 Load(args->at(2)); | 3590 Load(args->at(2)); |
(...skipping 1492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5082 __ tst(r3, Operand(kIsSymbolMask)); | 5083 __ tst(r3, Operand(kIsSymbolMask)); |
5083 __ b(eq, slow); | 5084 __ b(eq, slow); |
5084 | 5085 |
5085 // Both are symbols. We already checked they weren't the same pointer | 5086 // Both are symbols. We already checked they weren't the same pointer |
5086 // so they are not equal. | 5087 // so they are not equal. |
5087 __ mov(r0, Operand(1)); // Non-zero indicates not equal. | 5088 __ mov(r0, Operand(1)); // Non-zero indicates not equal. |
5088 __ mov(pc, Operand(lr)); // Return. | 5089 __ mov(pc, Operand(lr)); // Return. |
5089 } | 5090 } |
5090 | 5091 |
5091 | 5092 |
5092 // On entry r0 and r1 are the things to be compared. On exit r0 is 0, | 5093 // On entry r0 (rhs) and r1 (lhs) are the values to be compared. |
5093 // positive or negative to indicate the result of the comparison. | 5094 // On exit r0 is 0, positive or negative to indicate the result of |
| 5095 // the comparison. |
5094 void CompareStub::Generate(MacroAssembler* masm) { | 5096 void CompareStub::Generate(MacroAssembler* masm) { |
5095 Label slow; // Call builtin. | 5097 Label slow; // Call builtin. |
5096 Label not_smis, both_loaded_as_doubles, lhs_not_nan; | 5098 Label not_smis, both_loaded_as_doubles, lhs_not_nan; |
5097 | 5099 |
5098 // NOTICE! This code is only reached after a smi-fast-case check, so | 5100 // NOTICE! This code is only reached after a smi-fast-case check, so |
5099 // it is certain that at least one operand isn't a smi. | 5101 // it is certain that at least one operand isn't a smi. |
5100 | 5102 |
5101 // Handle the case where the objects are identical. Either returns the answer | 5103 // Handle the case where the objects are identical. Either returns the answer |
5102 // or goes to slow. Only falls through if the objects were not identical. | 5104 // or goes to slow. Only falls through if the objects were not identical. |
5103 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); | 5105 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5161 __ bind(¬_smis); | 5163 __ bind(¬_smis); |
5162 // At this point we know we are dealing with two different objects, | 5164 // At this point we know we are dealing with two different objects, |
5163 // and neither of them is a Smi. The objects are in r0 and r1. | 5165 // and neither of them is a Smi. The objects are in r0 and r1. |
5164 if (strict_) { | 5166 if (strict_) { |
5165 // This returns non-equal for some object types, or falls through if it | 5167 // This returns non-equal for some object types, or falls through if it |
5166 // was not lucky. | 5168 // was not lucky. |
5167 EmitStrictTwoHeapObjectCompare(masm); | 5169 EmitStrictTwoHeapObjectCompare(masm); |
5168 } | 5170 } |
5169 | 5171 |
5170 Label check_for_symbols; | 5172 Label check_for_symbols; |
| 5173 Label flat_string_check; |
5171 // Check for heap-number-heap-number comparison. Can jump to slow case, | 5174 // Check for heap-number-heap-number comparison. Can jump to slow case, |
5172 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles | 5175 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles |
5173 // that case. If the inputs are not doubles then jumps to check_for_symbols. | 5176 // that case. If the inputs are not doubles then jumps to check_for_symbols. |
5174 // In this case r2 will contain the type of r0. Never falls through. | 5177 // In this case r2 will contain the type of r0. Never falls through. |
5175 EmitCheckForTwoHeapNumbers(masm, | 5178 EmitCheckForTwoHeapNumbers(masm, |
5176 &both_loaded_as_doubles, | 5179 &both_loaded_as_doubles, |
5177 &check_for_symbols, | 5180 &check_for_symbols, |
5178 &slow); | 5181 &flat_string_check); |
5179 | 5182 |
5180 __ bind(&check_for_symbols); | 5183 __ bind(&check_for_symbols); |
5181 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of | 5184 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of |
5182 // symbols. | 5185 // symbols. |
5183 if (cc_ == eq && !strict_) { | 5186 if (cc_ == eq && !strict_) { |
5184 // Either jumps to slow or returns the answer. Assumes that r2 is the type | 5187 // Either jumps to slow or returns the answer. Assumes that r2 is the type |
5185 // of r0 on entry. | 5188 // of r0 on entry. |
5186 EmitCheckForSymbols(masm, &slow); | 5189 EmitCheckForSymbols(masm, &flat_string_check); |
5187 } | 5190 } |
5188 | 5191 |
| 5192 // Check for both being sequential ASCII strings, and inline if that is the |
| 5193 // case. |
| 5194 __ bind(&flat_string_check); |
| 5195 |
| 5196 __ JumpIfNonSmisNotBothSequentialAsciiStrings(r0, r1, r2, r3, &slow); |
| 5197 |
| 5198 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); |
| 5199 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
| 5200 r1, |
| 5201 r0, |
| 5202 r2, |
| 5203 r3, |
| 5204 r4, |
| 5205 r5); |
| 5206 // Never falls through to here. |
| 5207 |
5189 __ bind(&slow); | 5208 __ bind(&slow); |
| 5209 |
5190 __ push(r1); | 5210 __ push(r1); |
5191 __ push(r0); | 5211 __ push(r0); |
5192 // Figure out which native to call and setup the arguments. | 5212 // Figure out which native to call and setup the arguments. |
5193 Builtins::JavaScript native; | 5213 Builtins::JavaScript native; |
5194 if (cc_ == eq) { | 5214 if (cc_ == eq) { |
5195 native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 5215 native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
5196 } else { | 5216 } else { |
5197 native = Builtins::COMPARE; | 5217 native = Builtins::COMPARE; |
5198 int ncr; // NaN compare result | 5218 int ncr; // NaN compare result |
5199 if (cc_ == lt || cc_ == le) { | 5219 if (cc_ == lt || cc_ == le) { |
(...skipping 1530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6730 | 6750 |
6731 int CompareStub::MinorKey() { | 6751 int CompareStub::MinorKey() { |
6732 // Encode the three parameters in a unique 16 bit value. | 6752 // Encode the three parameters in a unique 16 bit value. |
6733 ASSERT((static_cast<unsigned>(cc_) >> 26) < (1 << 16)); | 6753 ASSERT((static_cast<unsigned>(cc_) >> 26) < (1 << 16)); |
6734 int nnn_value = (never_nan_nan_ ? 2 : 0); | 6754 int nnn_value = (never_nan_nan_ ? 2 : 0); |
6735 if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs. | 6755 if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs. |
6736 return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0); | 6756 return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0); |
6737 } | 6757 } |
6738 | 6758 |
6739 | 6759 |
| 6760 |
| 6761 |
| 6762 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 6763 Register left, |
| 6764 Register right, |
| 6765 Register scratch1, |
| 6766 Register scratch2, |
| 6767 Register scratch3, |
| 6768 Register scratch4) { |
| 6769 Label compare_lengths; |
| 6770 // Find minimum length and length difference. |
| 6771 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); |
| 6772 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
| 6773 __ sub(scratch3, scratch1, Operand(scratch2), SetCC); |
| 6774 Register length_delta = scratch3; |
| 6775 __ mov(scratch1, scratch2, LeaveCC, gt); |
| 6776 Register min_length = scratch1; |
| 6777 __ tst(min_length, Operand(min_length)); |
| 6778 __ b(eq, &compare_lengths); |
| 6779 |
| 6780 // Setup registers so that we only need to increment one register |
| 6781 // in the loop. |
| 6782 __ add(scratch2, min_length, |
| 6783 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 6784 __ add(left, left, Operand(scratch2)); |
| 6785 __ add(right, right, Operand(scratch2)); |
| 6786 // Registers left and right points to the min_length character of strings. |
| 6787 __ rsb(min_length, min_length, Operand(-1)); |
| 6788 Register index = min_length; |
| 6789 // Index starts at -min_length. |
| 6790 |
| 6791 { |
| 6792 // Compare loop. |
| 6793 Label loop; |
| 6794 __ bind(&loop); |
| 6795 // Compare characters. |
| 6796 __ add(index, index, Operand(1), SetCC); |
| 6797 __ ldrb(scratch2, MemOperand(left, index), ne); |
| 6798 __ ldrb(scratch4, MemOperand(right, index), ne); |
| 6799 // Skip to compare lengths with eq condition true. |
| 6800 __ b(eq, &compare_lengths); |
| 6801 __ cmp(scratch2, scratch4); |
| 6802 __ b(eq, &loop); |
| 6803 // Fallthrough with eq condition false. |
| 6804 } |
| 6805 // Compare lengths - strings up to min-length are equal. |
| 6806 __ bind(&compare_lengths); |
| 6807 ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); |
| 6808 // Use zero length_delta as result. |
| 6809 __ mov(r0, Operand(length_delta), SetCC, eq); |
| 6810 // Fall through to here if characters compare not-equal. |
| 6811 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt); |
| 6812 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt); |
| 6813 __ Ret(); |
| 6814 } |
| 6815 |
| 6816 |
| 6817 void StringCompareStub::Generate(MacroAssembler* masm) { |
| 6818 Label runtime; |
| 6819 |
| 6820 // Stack frame on entry. |
| 6821 // sp[0]: return address |
| 6822 // sp[4]: right string |
| 6823 // sp[8]: left string |
| 6824 |
| 6825 __ ldr(r0, MemOperand(sp, 2 * kPointerSize)); // left |
| 6826 __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // right |
| 6827 |
| 6828 Label not_same; |
| 6829 __ cmp(r0, r1); |
| 6830 __ b(ne, ¬_same); |
| 6831 ASSERT_EQ(0, EQUAL); |
| 6832 ASSERT_EQ(0, kSmiTag); |
| 6833 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
| 6834 __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2); |
| 6835 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 6836 __ Ret(); |
| 6837 |
| 6838 __ bind(¬_same); |
| 6839 |
| 6840 // Check that both objects are sequential ascii strings. |
| 6841 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime); |
| 6842 |
| 6843 // Compare flat ascii strings natively. Remove arguments from stack first. |
| 6844 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); |
| 6845 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 6846 GenerateCompareFlatAsciiStrings(masm, r0, r1, r2, r3, r4, r5); |
| 6847 |
| 6848 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 6849 // tagged as a small integer. |
| 6850 __ bind(&runtime); |
| 6851 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
| 6852 } |
| 6853 |
| 6854 |
6740 #undef __ | 6855 #undef __ |
6741 | 6856 |
6742 } } // namespace v8::internal | 6857 } } // namespace v8::internal |
OLD | NEW |