OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
8 | 8 |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of | 681 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of |
682 // internalized strings. | 682 // internalized strings. |
683 if (cc == eq && !strict()) { | 683 if (cc == eq && !strict()) { |
684 // Returns an answer for two internalized strings or two detectable objects. | 684 // Returns an answer for two internalized strings or two detectable objects. |
685 // Otherwise jumps to string case or not both strings case. | 685 // Otherwise jumps to string case or not both strings case. |
686 // Assumes that r2 is the type of rhs_ on entry. | 686 // Assumes that r2 is the type of rhs_ on entry. |
687 EmitCheckForInternalizedStringsOrObjects( | 687 EmitCheckForInternalizedStringsOrObjects( |
688 masm, lhs, rhs, &flat_string_check, &slow); | 688 masm, lhs, rhs, &flat_string_check, &slow); |
689 } | 689 } |
690 | 690 |
691 // Check for both being sequential ASCII strings, and inline if that is the | 691 // Check for both being sequential one-byte strings, |
692 // case. | 692 // and inline if that is the case. |
693 __ bind(&flat_string_check); | 693 __ bind(&flat_string_check); |
694 | 694 |
695 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow); | 695 __ JumpIfNonSmisNotBothSequentialOneByteStrings(lhs, rhs, r2, r3, &slow); |
696 | 696 |
697 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r2, | 697 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r2, |
698 r3); | 698 r3); |
699 if (cc == eq) { | 699 if (cc == eq) { |
700 StringHelper::GenerateFlatAsciiStringEquals(masm, lhs, rhs, r2, r3, r4); | 700 StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, r2, r3, r4); |
701 } else { | 701 } else { |
702 StringHelper::GenerateCompareFlatAsciiStrings(masm, lhs, rhs, r2, r3, r4, | 702 StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, r2, r3, r4, |
703 r5); | 703 r5); |
704 } | 704 } |
705 // Never falls through to here. | 705 // Never falls through to here. |
706 | 706 |
707 __ bind(&slow); | 707 __ bind(&slow); |
708 | 708 |
709 __ Push(lhs, rhs); | 709 __ Push(lhs, rhs); |
710 // Figure out which native to call and setup the arguments. | 710 // Figure out which native to call and setup the arguments. |
711 Builtins::JavaScript native; | 711 Builtins::JavaScript native; |
712 if (cc == eq) { | 712 if (cc == eq) { |
713 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 713 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
(...skipping 1316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2030 __ JumpIfNotSmi(r1, &runtime); | 2030 __ JumpIfNotSmi(r1, &runtime); |
2031 __ ldr(r3, FieldMemOperand(r3, String::kLengthOffset)); | 2031 __ ldr(r3, FieldMemOperand(r3, String::kLengthOffset)); |
2032 __ cmp(r3, Operand(r1)); | 2032 __ cmp(r3, Operand(r1)); |
2033 __ b(ls, &runtime); | 2033 __ b(ls, &runtime); |
2034 __ SmiUntag(r1); | 2034 __ SmiUntag(r1); |
2035 | 2035 |
2036 STATIC_ASSERT(4 == kOneByteStringTag); | 2036 STATIC_ASSERT(4 == kOneByteStringTag); |
2037 STATIC_ASSERT(kTwoByteStringTag == 0); | 2037 STATIC_ASSERT(kTwoByteStringTag == 0); |
2038 __ and_(r0, r0, Operand(kStringEncodingMask)); | 2038 __ and_(r0, r0, Operand(kStringEncodingMask)); |
2039 __ mov(r3, Operand(r0, ASR, 2), SetCC); | 2039 __ mov(r3, Operand(r0, ASR, 2), SetCC); |
2040 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); | 2040 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataOneByteCodeOffset), |
| 2041 ne); |
2041 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); | 2042 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); |
2042 | 2043 |
2043 // (E) Carry on. String handling is done. | 2044 // (E) Carry on. String handling is done. |
2044 // r6: irregexp code | 2045 // r6: irregexp code |
2045 // Check that the irregexp code has been generated for the actual string | 2046 // Check that the irregexp code has been generated for the actual string |
2046 // encoding. If it has, the field contains a code object otherwise it contains | 2047 // encoding. If it has, the field contains a code object otherwise it contains |
2047 // a smi (code flushing support). | 2048 // a smi (code flushing support). |
2048 __ JumpIfSmi(r6, &runtime); | 2049 __ JumpIfSmi(r6, &runtime); |
2049 | 2050 |
2050 // r1: previous index | 2051 // r1: previous index |
2051 // r3: encoding of subject string (1 if ASCII, 0 if two_byte); | 2052 // r3: encoding of subject string (1 if one_byte, 0 if two_byte); |
2052 // r6: code | 2053 // r6: code |
2053 // subject: Subject string | 2054 // subject: Subject string |
2054 // regexp_data: RegExp data (FixedArray) | 2055 // regexp_data: RegExp data (FixedArray) |
2055 // All checks done. Now push arguments for native regexp code. | 2056 // All checks done. Now push arguments for native regexp code. |
2056 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, r0, r2); | 2057 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, r0, r2); |
2057 | 2058 |
2058 // Isolates: note we add an additional parameter here (isolate pointer). | 2059 // Isolates: note we add an additional parameter here (isolate pointer). |
2059 const int kRegExpExecuteArguments = 9; | 2060 const int kRegExpExecuteArguments = 9; |
2060 const int kParameterRegisters = 4; | 2061 const int kParameterRegisters = 4; |
2061 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); | 2062 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); |
(...skipping 22 matching lines...) Expand all Loading... |
2084 __ mov(r0, Operand::Zero()); | 2085 __ mov(r0, Operand::Zero()); |
2085 __ str(r0, MemOperand(sp, 2 * kPointerSize)); | 2086 __ str(r0, MemOperand(sp, 2 * kPointerSize)); |
2086 | 2087 |
2087 // Argument 5 (sp[4]): static offsets vector buffer. | 2088 // Argument 5 (sp[4]): static offsets vector buffer. |
2088 __ mov(r0, | 2089 __ mov(r0, |
2089 Operand(ExternalReference::address_of_static_offsets_vector( | 2090 Operand(ExternalReference::address_of_static_offsets_vector( |
2090 isolate()))); | 2091 isolate()))); |
2091 __ str(r0, MemOperand(sp, 1 * kPointerSize)); | 2092 __ str(r0, MemOperand(sp, 1 * kPointerSize)); |
2092 | 2093 |
2093 // For arguments 4 and 3 get string length, calculate start of string data and | 2094 // For arguments 4 and 3 get string length, calculate start of string data and |
2094 // calculate the shift of the index (0 for ASCII and 1 for two byte). | 2095 // calculate the shift of the index (0 for one-byte and 1 for two-byte). |
2095 __ add(r7, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); | 2096 __ add(r7, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); |
2096 __ eor(r3, r3, Operand(1)); | 2097 __ eor(r3, r3, Operand(1)); |
2097 // Load the length from the original subject string from the previous stack | 2098 // Load the length from the original subject string from the previous stack |
2098 // frame. Therefore we have to use fp, which points exactly to two pointer | 2099 // frame. Therefore we have to use fp, which points exactly to two pointer |
2099 // sizes below the previous sp. (Because creating a new stack frame pushes | 2100 // sizes below the previous sp. (Because creating a new stack frame pushes |
2100 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) | 2101 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) |
2101 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); | 2102 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); |
2102 // If slice offset is not 0, load the length from the original sliced string. | 2103 // If slice offset is not 0, load the length from the original sliced string. |
2103 // Argument 4, r3: End of string data | 2104 // Argument 4, r3: End of string data |
2104 // Argument 3, r2: Start of string data | 2105 // Argument 3, r2: Start of string data |
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2717 __ CallExternalReference(miss, 4); | 2718 __ CallExternalReference(miss, 4); |
2718 | 2719 |
2719 // Move result to edi and exit the internal frame. | 2720 // Move result to edi and exit the internal frame. |
2720 __ mov(r1, r0); | 2721 __ mov(r1, r0); |
2721 } | 2722 } |
2722 } | 2723 } |
2723 | 2724 |
2724 | 2725 |
2725 // StringCharCodeAtGenerator | 2726 // StringCharCodeAtGenerator |
2726 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 2727 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
2727 Label flat_string; | |
2728 Label ascii_string; | |
2729 Label got_char_code; | |
2730 Label sliced_string; | |
2731 | |
2732 // If the receiver is a smi trigger the non-string case. | 2728 // If the receiver is a smi trigger the non-string case. |
2733 __ JumpIfSmi(object_, receiver_not_string_); | 2729 __ JumpIfSmi(object_, receiver_not_string_); |
2734 | 2730 |
2735 // Fetch the instance type of the receiver into result register. | 2731 // Fetch the instance type of the receiver into result register. |
2736 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 2732 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
2737 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 2733 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
2738 // If the receiver is not a string trigger the non-string case. | 2734 // If the receiver is not a string trigger the non-string case. |
2739 __ tst(result_, Operand(kIsNotStringMask)); | 2735 __ tst(result_, Operand(kIsNotStringMask)); |
2740 __ b(ne, receiver_not_string_); | 2736 __ b(ne, receiver_not_string_); |
2741 | 2737 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2820 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 2816 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
2821 STATIC_ASSERT(kSmiTag == 0); | 2817 STATIC_ASSERT(kSmiTag == 0); |
2822 STATIC_ASSERT(kSmiShiftSize == 0); | 2818 STATIC_ASSERT(kSmiShiftSize == 0); |
2823 DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCode + 1)); | 2819 DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCode + 1)); |
2824 __ tst(code_, | 2820 __ tst(code_, |
2825 Operand(kSmiTagMask | | 2821 Operand(kSmiTagMask | |
2826 ((~String::kMaxOneByteCharCode) << kSmiTagSize))); | 2822 ((~String::kMaxOneByteCharCode) << kSmiTagSize))); |
2827 __ b(ne, &slow_case_); | 2823 __ b(ne, &slow_case_); |
2828 | 2824 |
2829 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); | 2825 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
2830 // At this point code register contains smi tagged ASCII char code. | 2826 // At this point code register contains smi tagged one-byte char code. |
2831 __ add(result_, result_, Operand::PointerOffsetFromSmiKey(code_)); | 2827 __ add(result_, result_, Operand::PointerOffsetFromSmiKey(code_)); |
2832 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); | 2828 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); |
2833 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); | 2829 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); |
2834 __ b(eq, &slow_case_); | 2830 __ b(eq, &slow_case_); |
2835 __ bind(&exit_); | 2831 __ bind(&exit_); |
2836 } | 2832 } |
2837 | 2833 |
2838 | 2834 |
2839 void StringCharFromCodeGenerator::GenerateSlow( | 2835 void StringCharFromCodeGenerator::GenerateSlow( |
2840 MacroAssembler* masm, | 2836 MacroAssembler* masm, |
2841 const RuntimeCallHelper& call_helper) { | 2837 const RuntimeCallHelper& call_helper) { |
2842 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); | 2838 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); |
2843 | 2839 |
2844 __ bind(&slow_case_); | 2840 __ bind(&slow_case_); |
2845 call_helper.BeforeCall(masm); | 2841 call_helper.BeforeCall(masm); |
2846 __ push(code_); | 2842 __ push(code_); |
2847 __ CallRuntime(Runtime::kCharFromCode, 1); | 2843 __ CallRuntime(Runtime::kCharFromCode, 1); |
2848 __ Move(result_, r0); | 2844 __ Move(result_, r0); |
2849 call_helper.AfterCall(masm); | 2845 call_helper.AfterCall(masm); |
2850 __ jmp(&exit_); | 2846 __ jmp(&exit_); |
2851 | 2847 |
2852 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 2848 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
2853 } | 2849 } |
2854 | 2850 |
2855 | 2851 |
2856 enum CopyCharactersFlags { | 2852 enum CopyCharactersFlags { COPY_ONE_BYTE = 1, DEST_ALWAYS_ALIGNED = 2 }; |
2857 COPY_ASCII = 1, | |
2858 DEST_ALWAYS_ALIGNED = 2 | |
2859 }; | |
2860 | 2853 |
2861 | 2854 |
2862 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | 2855 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
2863 Register dest, | 2856 Register dest, |
2864 Register src, | 2857 Register src, |
2865 Register count, | 2858 Register count, |
2866 Register scratch, | 2859 Register scratch, |
2867 String::Encoding encoding) { | 2860 String::Encoding encoding) { |
2868 if (FLAG_debug_code) { | 2861 if (FLAG_debug_code) { |
2869 // Check that destination is word aligned. | 2862 // Check that destination is word aligned. |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3010 // Allocate new sliced string. At this point we do not reload the instance | 3003 // Allocate new sliced string. At this point we do not reload the instance |
3011 // type including the string encoding because we simply rely on the info | 3004 // type including the string encoding because we simply rely on the info |
3012 // provided by the original string. It does not matter if the original | 3005 // provided by the original string. It does not matter if the original |
3013 // string's encoding is wrong because we always have to recheck encoding of | 3006 // string's encoding is wrong because we always have to recheck encoding of |
3014 // the newly created string's parent anyways due to externalized strings. | 3007 // the newly created string's parent anyways due to externalized strings. |
3015 Label two_byte_slice, set_slice_header; | 3008 Label two_byte_slice, set_slice_header; |
3016 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | 3009 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); |
3017 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 3010 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
3018 __ tst(r1, Operand(kStringEncodingMask)); | 3011 __ tst(r1, Operand(kStringEncodingMask)); |
3019 __ b(eq, &two_byte_slice); | 3012 __ b(eq, &two_byte_slice); |
3020 __ AllocateAsciiSlicedString(r0, r2, r6, r4, &runtime); | 3013 __ AllocateOneByteSlicedString(r0, r2, r6, r4, &runtime); |
3021 __ jmp(&set_slice_header); | 3014 __ jmp(&set_slice_header); |
3022 __ bind(&two_byte_slice); | 3015 __ bind(&two_byte_slice); |
3023 __ AllocateTwoByteSlicedString(r0, r2, r6, r4, &runtime); | 3016 __ AllocateTwoByteSlicedString(r0, r2, r6, r4, &runtime); |
3024 __ bind(&set_slice_header); | 3017 __ bind(&set_slice_header); |
3025 __ mov(r3, Operand(r3, LSL, 1)); | 3018 __ mov(r3, Operand(r3, LSL, 1)); |
3026 __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); | 3019 __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); |
3027 __ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset)); | 3020 __ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset)); |
3028 __ jmp(&return_r0); | 3021 __ jmp(&return_r0); |
3029 | 3022 |
3030 __ bind(©_routine); | 3023 __ bind(©_routine); |
(...skipping 22 matching lines...) Expand all Loading... |
3053 // Locate first character of underlying subject string. | 3046 // Locate first character of underlying subject string. |
3054 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 3047 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
3055 __ add(r5, r5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3048 __ add(r5, r5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
3056 | 3049 |
3057 __ bind(&allocate_result); | 3050 __ bind(&allocate_result); |
3058 // Sequential acii string. Allocate the result. | 3051 // Sequential acii string. Allocate the result. |
3059 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | 3052 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); |
3060 __ tst(r1, Operand(kStringEncodingMask)); | 3053 __ tst(r1, Operand(kStringEncodingMask)); |
3061 __ b(eq, &two_byte_sequential); | 3054 __ b(eq, &two_byte_sequential); |
3062 | 3055 |
3063 // Allocate and copy the resulting ASCII string. | 3056 // Allocate and copy the resulting one-byte string. |
3064 __ AllocateAsciiString(r0, r2, r4, r6, r1, &runtime); | 3057 __ AllocateOneByteString(r0, r2, r4, r6, r1, &runtime); |
3065 | 3058 |
3066 // Locate first character of substring to copy. | 3059 // Locate first character of substring to copy. |
3067 __ add(r5, r5, r3); | 3060 __ add(r5, r5, r3); |
3068 // Locate first character of result. | 3061 // Locate first character of result. |
3069 __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3062 __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
3070 | 3063 |
3071 // r0: result string | 3064 // r0: result string |
3072 // r1: first character of result string | 3065 // r1: first character of result string |
3073 // r2: result string length | 3066 // r2: result string length |
3074 // r5: first character of substring to copy | 3067 // r5: first character of substring to copy |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3113 __ SmiTag(r3, r3); | 3106 __ SmiTag(r3, r3); |
3114 StringCharAtGenerator generator( | 3107 StringCharAtGenerator generator( |
3115 r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); | 3108 r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); |
3116 generator.GenerateFast(masm); | 3109 generator.GenerateFast(masm); |
3117 __ Drop(3); | 3110 __ Drop(3); |
3118 __ Ret(); | 3111 __ Ret(); |
3119 generator.SkipSlow(masm, &runtime); | 3112 generator.SkipSlow(masm, &runtime); |
3120 } | 3113 } |
3121 | 3114 |
3122 | 3115 |
3123 void StringHelper::GenerateFlatAsciiStringEquals(MacroAssembler* masm, | 3116 void StringHelper::GenerateFlatOneByteStringEquals( |
3124 Register left, Register right, | 3117 MacroAssembler* masm, Register left, Register right, Register scratch1, |
3125 Register scratch1, | 3118 Register scratch2, Register scratch3) { |
3126 Register scratch2, | |
3127 Register scratch3) { | |
3128 Register length = scratch1; | 3119 Register length = scratch1; |
3129 | 3120 |
3130 // Compare lengths. | 3121 // Compare lengths. |
3131 Label strings_not_equal, check_zero_length; | 3122 Label strings_not_equal, check_zero_length; |
3132 __ ldr(length, FieldMemOperand(left, String::kLengthOffset)); | 3123 __ ldr(length, FieldMemOperand(left, String::kLengthOffset)); |
3133 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); | 3124 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
3134 __ cmp(length, scratch2); | 3125 __ cmp(length, scratch2); |
3135 __ b(eq, &check_zero_length); | 3126 __ b(eq, &check_zero_length); |
3136 __ bind(&strings_not_equal); | 3127 __ bind(&strings_not_equal); |
3137 __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL))); | 3128 __ mov(r0, Operand(Smi::FromInt(NOT_EQUAL))); |
3138 __ Ret(); | 3129 __ Ret(); |
3139 | 3130 |
3140 // Check if the length is zero. | 3131 // Check if the length is zero. |
3141 Label compare_chars; | 3132 Label compare_chars; |
3142 __ bind(&check_zero_length); | 3133 __ bind(&check_zero_length); |
3143 STATIC_ASSERT(kSmiTag == 0); | 3134 STATIC_ASSERT(kSmiTag == 0); |
3144 __ cmp(length, Operand::Zero()); | 3135 __ cmp(length, Operand::Zero()); |
3145 __ b(ne, &compare_chars); | 3136 __ b(ne, &compare_chars); |
3146 __ mov(r0, Operand(Smi::FromInt(EQUAL))); | 3137 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
3147 __ Ret(); | 3138 __ Ret(); |
3148 | 3139 |
3149 // Compare characters. | 3140 // Compare characters. |
3150 __ bind(&compare_chars); | 3141 __ bind(&compare_chars); |
3151 GenerateAsciiCharsCompareLoop(masm, | 3142 GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2, scratch3, |
3152 left, right, length, scratch2, scratch3, | 3143 &strings_not_equal); |
3153 &strings_not_equal); | |
3154 | 3144 |
3155 // Characters are equal. | 3145 // Characters are equal. |
3156 __ mov(r0, Operand(Smi::FromInt(EQUAL))); | 3146 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
3157 __ Ret(); | 3147 __ Ret(); |
3158 } | 3148 } |
3159 | 3149 |
3160 | 3150 |
3161 void StringHelper::GenerateCompareFlatAsciiStrings( | 3151 void StringHelper::GenerateCompareFlatOneByteStrings( |
3162 MacroAssembler* masm, Register left, Register right, Register scratch1, | 3152 MacroAssembler* masm, Register left, Register right, Register scratch1, |
3163 Register scratch2, Register scratch3, Register scratch4) { | 3153 Register scratch2, Register scratch3, Register scratch4) { |
3164 Label result_not_equal, compare_lengths; | 3154 Label result_not_equal, compare_lengths; |
3165 // Find minimum length and length difference. | 3155 // Find minimum length and length difference. |
3166 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); | 3156 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); |
3167 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); | 3157 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
3168 __ sub(scratch3, scratch1, Operand(scratch2), SetCC); | 3158 __ sub(scratch3, scratch1, Operand(scratch2), SetCC); |
3169 Register length_delta = scratch3; | 3159 Register length_delta = scratch3; |
3170 __ mov(scratch1, scratch2, LeaveCC, gt); | 3160 __ mov(scratch1, scratch2, LeaveCC, gt); |
3171 Register min_length = scratch1; | 3161 Register min_length = scratch1; |
3172 STATIC_ASSERT(kSmiTag == 0); | 3162 STATIC_ASSERT(kSmiTag == 0); |
3173 __ cmp(min_length, Operand::Zero()); | 3163 __ cmp(min_length, Operand::Zero()); |
3174 __ b(eq, &compare_lengths); | 3164 __ b(eq, &compare_lengths); |
3175 | 3165 |
3176 // Compare loop. | 3166 // Compare loop. |
3177 GenerateAsciiCharsCompareLoop(masm, | 3167 GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2, |
3178 left, right, min_length, scratch2, scratch4, | 3168 scratch4, &result_not_equal); |
3179 &result_not_equal); | |
3180 | 3169 |
3181 // Compare lengths - strings up to min-length are equal. | 3170 // Compare lengths - strings up to min-length are equal. |
3182 __ bind(&compare_lengths); | 3171 __ bind(&compare_lengths); |
3183 DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); | 3172 DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); |
3184 // Use length_delta as result if it's zero. | 3173 // Use length_delta as result if it's zero. |
3185 __ mov(r0, Operand(length_delta), SetCC); | 3174 __ mov(r0, Operand(length_delta), SetCC); |
3186 __ bind(&result_not_equal); | 3175 __ bind(&result_not_equal); |
3187 // Conditionally update the result based either on length_delta or | 3176 // Conditionally update the result based either on length_delta or |
3188 // the last comparion performed in the loop above. | 3177 // the last comparion performed in the loop above. |
3189 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt); | 3178 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt); |
3190 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt); | 3179 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt); |
3191 __ Ret(); | 3180 __ Ret(); |
3192 } | 3181 } |
3193 | 3182 |
3194 | 3183 |
3195 void StringHelper::GenerateAsciiCharsCompareLoop( | 3184 void StringHelper::GenerateOneByteCharsCompareLoop( |
3196 MacroAssembler* masm, Register left, Register right, Register length, | 3185 MacroAssembler* masm, Register left, Register right, Register length, |
3197 Register scratch1, Register scratch2, Label* chars_not_equal) { | 3186 Register scratch1, Register scratch2, Label* chars_not_equal) { |
3198 // Change index to run from -length to -1 by adding length to string | 3187 // Change index to run from -length to -1 by adding length to string |
3199 // start. This means that loop ends when index reaches zero, which | 3188 // start. This means that loop ends when index reaches zero, which |
3200 // doesn't need an additional compare. | 3189 // doesn't need an additional compare. |
3201 __ SmiUntag(length); | 3190 __ SmiUntag(length); |
3202 __ add(scratch1, length, | 3191 __ add(scratch1, length, |
3203 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3192 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
3204 __ add(left, left, Operand(scratch1)); | 3193 __ add(left, left, Operand(scratch1)); |
3205 __ add(right, right, Operand(scratch1)); | 3194 __ add(right, right, Operand(scratch1)); |
(...skipping 27 matching lines...) Expand all Loading... |
3233 __ b(ne, ¬_same); | 3222 __ b(ne, ¬_same); |
3234 STATIC_ASSERT(EQUAL == 0); | 3223 STATIC_ASSERT(EQUAL == 0); |
3235 STATIC_ASSERT(kSmiTag == 0); | 3224 STATIC_ASSERT(kSmiTag == 0); |
3236 __ mov(r0, Operand(Smi::FromInt(EQUAL))); | 3225 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
3237 __ IncrementCounter(counters->string_compare_native(), 1, r1, r2); | 3226 __ IncrementCounter(counters->string_compare_native(), 1, r1, r2); |
3238 __ add(sp, sp, Operand(2 * kPointerSize)); | 3227 __ add(sp, sp, Operand(2 * kPointerSize)); |
3239 __ Ret(); | 3228 __ Ret(); |
3240 | 3229 |
3241 __ bind(¬_same); | 3230 __ bind(¬_same); |
3242 | 3231 |
3243 // Check that both objects are sequential ASCII strings. | 3232 // Check that both objects are sequential one-byte strings. |
3244 __ JumpIfNotBothSequentialAsciiStrings(r1, r0, r2, r3, &runtime); | 3233 __ JumpIfNotBothSequentialOneByteStrings(r1, r0, r2, r3, &runtime); |
3245 | 3234 |
3246 // Compare flat ASCII strings natively. Remove arguments from stack first. | 3235 // Compare flat one-byte strings natively. Remove arguments from stack first. |
3247 __ IncrementCounter(counters->string_compare_native(), 1, r2, r3); | 3236 __ IncrementCounter(counters->string_compare_native(), 1, r2, r3); |
3248 __ add(sp, sp, Operand(2 * kPointerSize)); | 3237 __ add(sp, sp, Operand(2 * kPointerSize)); |
3249 StringHelper::GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5); | 3238 StringHelper::GenerateCompareFlatOneByteStrings(masm, r1, r0, r2, r3, r4, r5); |
3250 | 3239 |
3251 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 3240 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
3252 // tagged as a small integer. | 3241 // tagged as a small integer. |
3253 __ bind(&runtime); | 3242 __ bind(&runtime); |
3254 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3243 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
3255 } | 3244 } |
3256 | 3245 |
3257 | 3246 |
3258 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { | 3247 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { |
3259 // ----------- S t a t e ------------- | 3248 // ----------- S t a t e ------------- |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3505 DCHECK(GetCondition() == eq); | 3494 DCHECK(GetCondition() == eq); |
3506 STATIC_ASSERT(kInternalizedTag == 0); | 3495 STATIC_ASSERT(kInternalizedTag == 0); |
3507 __ orr(tmp3, tmp1, Operand(tmp2)); | 3496 __ orr(tmp3, tmp1, Operand(tmp2)); |
3508 __ tst(tmp3, Operand(kIsNotInternalizedMask)); | 3497 __ tst(tmp3, Operand(kIsNotInternalizedMask)); |
3509 // Make sure r0 is non-zero. At this point input operands are | 3498 // Make sure r0 is non-zero. At this point input operands are |
3510 // guaranteed to be non-zero. | 3499 // guaranteed to be non-zero. |
3511 DCHECK(right.is(r0)); | 3500 DCHECK(right.is(r0)); |
3512 __ Ret(eq); | 3501 __ Ret(eq); |
3513 } | 3502 } |
3514 | 3503 |
3515 // Check that both strings are sequential ASCII. | 3504 // Check that both strings are sequential one-byte. |
3516 Label runtime; | 3505 Label runtime; |
3517 __ JumpIfBothInstanceTypesAreNotSequentialAscii( | 3506 __ JumpIfBothInstanceTypesAreNotSequentialOneByte(tmp1, tmp2, tmp3, tmp4, |
3518 tmp1, tmp2, tmp3, tmp4, &runtime); | 3507 &runtime); |
3519 | 3508 |
3520 // Compare flat ASCII strings. Returns when done. | 3509 // Compare flat one-byte strings. Returns when done. |
3521 if (equality) { | 3510 if (equality) { |
3522 StringHelper::GenerateFlatAsciiStringEquals(masm, left, right, tmp1, tmp2, | 3511 StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1, tmp2, |
3523 tmp3); | 3512 tmp3); |
3524 } else { | 3513 } else { |
3525 StringHelper::GenerateCompareFlatAsciiStrings(masm, left, right, tmp1, tmp2, | 3514 StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, tmp1, |
3526 tmp3, tmp4); | 3515 tmp2, tmp3, tmp4); |
3527 } | 3516 } |
3528 | 3517 |
3529 // Handle more complex cases in runtime. | 3518 // Handle more complex cases in runtime. |
3530 __ bind(&runtime); | 3519 __ bind(&runtime); |
3531 __ Push(left, right); | 3520 __ Push(left, right); |
3532 if (equality) { | 3521 if (equality) { |
3533 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); | 3522 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
3534 } else { | 3523 } else { |
3535 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3524 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
3536 } | 3525 } |
(...skipping 1118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4655 MemOperand(fp, 6 * kPointerSize), | 4644 MemOperand(fp, 6 * kPointerSize), |
4656 NULL); | 4645 NULL); |
4657 } | 4646 } |
4658 | 4647 |
4659 | 4648 |
4660 #undef __ | 4649 #undef __ |
4661 | 4650 |
4662 } } // namespace v8::internal | 4651 } } // namespace v8::internal |
4663 | 4652 |
4664 #endif // V8_TARGET_ARCH_ARM | 4653 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |