OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
8 | 8 |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 // In the strict case, the EmitStrictTwoHeapObjectCompare already took care | 596 // In the strict case, the EmitStrictTwoHeapObjectCompare already took care |
597 // of internalized strings. | 597 // of internalized strings. |
598 if ((cond == eq) && !strict()) { | 598 if ((cond == eq) && !strict()) { |
599 // Returns an answer for two internalized strings or two detectable objects. | 599 // Returns an answer for two internalized strings or two detectable objects. |
600 // Otherwise branches to the string case or not both strings case. | 600 // Otherwise branches to the string case or not both strings case. |
601 EmitCheckForInternalizedStringsOrObjects(masm, lhs, rhs, lhs_map, rhs_map, | 601 EmitCheckForInternalizedStringsOrObjects(masm, lhs, rhs, lhs_map, rhs_map, |
602 lhs_type, rhs_type, | 602 lhs_type, rhs_type, |
603 &flat_string_check, &slow); | 603 &flat_string_check, &slow); |
604 } | 604 } |
605 | 605 |
606 // Check for both being sequential ASCII strings, and inline if that is the | 606 // Check for both being sequential one-byte strings, |
607 // case. | 607 // and inline if that is the case. |
608 __ Bind(&flat_string_check); | 608 __ Bind(&flat_string_check); |
609 __ JumpIfBothInstanceTypesAreNotSequentialAscii(lhs_type, rhs_type, x14, | 609 __ JumpIfBothInstanceTypesAreNotSequentialOneByte(lhs_type, rhs_type, x14, |
610 x15, &slow); | 610 x15, &slow); |
611 | 611 |
612 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, x10, | 612 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, x10, |
613 x11); | 613 x11); |
614 if (cond == eq) { | 614 if (cond == eq) { |
615 StringHelper::GenerateFlatAsciiStringEquals(masm, lhs, rhs, x10, x11, x12); | 615 StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, x10, x11, |
| 616 x12); |
616 } else { | 617 } else { |
617 StringHelper::GenerateCompareFlatAsciiStrings(masm, lhs, rhs, x10, x11, x12, | 618 StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, x10, x11, |
618 x13); | 619 x12, x13); |
619 } | 620 } |
620 | 621 |
621 // Never fall through to here. | 622 // Never fall through to here. |
622 if (FLAG_debug_code) { | 623 if (FLAG_debug_code) { |
623 __ Unreachable(); | 624 __ Unreachable(); |
624 } | 625 } |
625 | 626 |
626 __ Bind(&slow); | 627 __ Bind(&slow); |
627 | 628 |
628 __ Push(lhs, rhs); | 629 __ Push(lhs, rhs); |
(...skipping 1470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2099 // jssp[24]: JSRegExp object | 2100 // jssp[24]: JSRegExp object |
2100 Label runtime; | 2101 Label runtime; |
2101 | 2102 |
2102 // Use of registers for this function. | 2103 // Use of registers for this function. |
2103 | 2104 |
2104 // Variable registers: | 2105 // Variable registers: |
2105 // x10-x13 used as scratch registers | 2106 // x10-x13 used as scratch registers |
2106 // w0 string_type type of subject string | 2107 // w0 string_type type of subject string |
2107 // x2 jsstring_length subject string length | 2108 // x2 jsstring_length subject string length |
2108 // x3 jsregexp_object JSRegExp object | 2109 // x3 jsregexp_object JSRegExp object |
2109 // w4 string_encoding ASCII or UC16 | 2110 // w4 string_encoding Latin1 or UC16 |
2110 // w5 sliced_string_offset if the string is a SlicedString | 2111 // w5 sliced_string_offset if the string is a SlicedString |
2111 // offset to the underlying string | 2112 // offset to the underlying string |
2112 // w6 string_representation groups attributes of the string: | 2113 // w6 string_representation groups attributes of the string: |
2113 // - is a string | 2114 // - is a string |
2114 // - type of the string | 2115 // - type of the string |
2115 // - is a short external string | 2116 // - is a short external string |
2116 Register string_type = w0; | 2117 Register string_type = w0; |
2117 Register jsstring_length = x2; | 2118 Register jsstring_length = x2; |
2118 Register jsregexp_object = x3; | 2119 Register jsregexp_object = x3; |
2119 Register string_encoding = w4; | 2120 Register string_encoding = w4; |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2297 // Argument 2 (x1): We need to load argument 2 (the previous index) into x1 | 2298 // Argument 2 (x1): We need to load argument 2 (the previous index) into x1 |
2298 // before entering the exit frame. | 2299 // before entering the exit frame. |
2299 __ SmiUntag(x1, x10); | 2300 __ SmiUntag(x1, x10); |
2300 | 2301 |
2301 // The third bit determines the string encoding in string_type. | 2302 // The third bit determines the string encoding in string_type. |
2302 STATIC_ASSERT(kOneByteStringTag == 0x04); | 2303 STATIC_ASSERT(kOneByteStringTag == 0x04); |
2303 STATIC_ASSERT(kTwoByteStringTag == 0x00); | 2304 STATIC_ASSERT(kTwoByteStringTag == 0x00); |
2304 STATIC_ASSERT(kStringEncodingMask == 0x04); | 2305 STATIC_ASSERT(kStringEncodingMask == 0x04); |
2305 | 2306 |
2306 // Find the code object based on the assumptions above. | 2307 // Find the code object based on the assumptions above. |
2307 // kDataAsciiCodeOffset and kDataUC16CodeOffset are adjacent, adds an offset | 2308 // kDataOneByteCodeOffset and kDataUC16CodeOffset are adjacent, adds an offset |
2308 // of kPointerSize to reach the latter. | 2309 // of kPointerSize to reach the latter. |
2309 DCHECK_EQ(JSRegExp::kDataAsciiCodeOffset + kPointerSize, | 2310 DCHECK_EQ(JSRegExp::kDataOneByteCodeOffset + kPointerSize, |
2310 JSRegExp::kDataUC16CodeOffset); | 2311 JSRegExp::kDataUC16CodeOffset); |
2311 __ Mov(x10, kPointerSize); | 2312 __ Mov(x10, kPointerSize); |
2312 // We will need the encoding later: ASCII = 0x04 | 2313 // We will need the encoding later: Latin1 = 0x04 |
2313 // UC16 = 0x00 | 2314 // UC16 = 0x00 |
2314 __ Ands(string_encoding, string_type, kStringEncodingMask); | 2315 __ Ands(string_encoding, string_type, kStringEncodingMask); |
2315 __ CzeroX(x10, ne); | 2316 __ CzeroX(x10, ne); |
2316 __ Add(x10, regexp_data, x10); | 2317 __ Add(x10, regexp_data, x10); |
2317 __ Ldr(code_object, FieldMemOperand(x10, JSRegExp::kDataAsciiCodeOffset)); | 2318 __ Ldr(code_object, FieldMemOperand(x10, JSRegExp::kDataOneByteCodeOffset)); |
2318 | 2319 |
2319 // (E) Carry on. String handling is done. | 2320 // (E) Carry on. String handling is done. |
2320 | 2321 |
2321 // Check that the irregexp code has been generated for the actual string | 2322 // Check that the irregexp code has been generated for the actual string |
2322 // encoding. If it has, the field contains a code object otherwise it contains | 2323 // encoding. If it has, the field contains a code object otherwise it contains |
2323 // a smi (code flushing support). | 2324 // a smi (code flushing support). |
2324 __ JumpIfSmi(code_object, &runtime); | 2325 __ JumpIfSmi(code_object, &runtime); |
2325 | 2326 |
2326 // All checks done. Now push arguments for native regexp code. | 2327 // All checks done. Now push arguments for native regexp code. |
2327 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, | 2328 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, |
(...skipping 22 matching lines...) Expand all Loading... |
2350 // Load start of the subject string. | 2351 // Load start of the subject string. |
2351 __ Add(start, subject, SeqString::kHeaderSize - kHeapObjectTag); | 2352 __ Add(start, subject, SeqString::kHeaderSize - kHeapObjectTag); |
2352 // Load the length from the original subject string from the previous stack | 2353 // Load the length from the original subject string from the previous stack |
2353 // frame. Therefore we have to use fp, which points exactly to two pointer | 2354 // frame. Therefore we have to use fp, which points exactly to two pointer |
2354 // sizes below the previous sp. (Because creating a new stack frame pushes | 2355 // sizes below the previous sp. (Because creating a new stack frame pushes |
2355 // the previous fp onto the stack and decrements sp by 2 * kPointerSize.) | 2356 // the previous fp onto the stack and decrements sp by 2 * kPointerSize.) |
2356 __ Ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); | 2357 __ Ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); |
2357 __ Ldr(length, UntagSmiFieldMemOperand(subject, String::kLengthOffset)); | 2358 __ Ldr(length, UntagSmiFieldMemOperand(subject, String::kLengthOffset)); |
2358 | 2359 |
2359 // Handle UC16 encoding, two bytes make one character. | 2360 // Handle UC16 encoding, two bytes make one character. |
2360 // string_encoding: if ASCII: 0x04 | 2361 // string_encoding: if Latin1: 0x04 |
2361 // if UC16: 0x00 | 2362 // if UC16: 0x00 |
2362 STATIC_ASSERT(kStringEncodingMask == 0x04); | 2363 STATIC_ASSERT(kStringEncodingMask == 0x04); |
2363 __ Ubfx(string_encoding, string_encoding, 2, 1); | 2364 __ Ubfx(string_encoding, string_encoding, 2, 1); |
2364 __ Eor(string_encoding, string_encoding, 1); | 2365 __ Eor(string_encoding, string_encoding, 1); |
2365 // string_encoding: if ASCII: 0 | 2366 // string_encoding: if Latin1: 0 |
2366 // if UC16: 1 | 2367 // if UC16: 1 |
2367 | 2368 |
2368 // Convert string positions from characters to bytes. | 2369 // Convert string positions from characters to bytes. |
2369 // Previous index is in x1. | 2370 // Previous index is in x1. |
2370 __ Lsl(previous_index_in_bytes, w1, string_encoding); | 2371 __ Lsl(previous_index_in_bytes, w1, string_encoding); |
2371 __ Lsl(length, length, string_encoding); | 2372 __ Lsl(length, length, string_encoding); |
2372 __ Lsl(sliced_string_offset, sliced_string_offset, string_encoding); | 2373 __ Lsl(sliced_string_offset, sliced_string_offset, string_encoding); |
2373 | 2374 |
2374 // Argument 1 (x0): Subject string. | 2375 // Argument 1 (x0): Subject string. |
2375 __ Mov(x0, subject); | 2376 __ Mov(x0, subject); |
2376 | 2377 |
(...skipping 775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3152 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); | 3153 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); |
3153 } | 3154 } |
3154 | 3155 |
3155 | 3156 |
3156 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 3157 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
3157 __ JumpIfNotSmi(code_, &slow_case_); | 3158 __ JumpIfNotSmi(code_, &slow_case_); |
3158 __ Cmp(code_, Smi::FromInt(String::kMaxOneByteCharCode)); | 3159 __ Cmp(code_, Smi::FromInt(String::kMaxOneByteCharCode)); |
3159 __ B(hi, &slow_case_); | 3160 __ B(hi, &slow_case_); |
3160 | 3161 |
3161 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); | 3162 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
3162 // At this point code register contains smi tagged ASCII char code. | 3163 // At this point code register contains smi tagged one-byte char code. |
3163 __ Add(result_, result_, Operand::UntagSmiAndScale(code_, kPointerSizeLog2)); | 3164 __ Add(result_, result_, Operand::UntagSmiAndScale(code_, kPointerSizeLog2)); |
3164 __ Ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); | 3165 __ Ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); |
3165 __ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_); | 3166 __ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_); |
3166 __ Bind(&exit_); | 3167 __ Bind(&exit_); |
3167 } | 3168 } |
3168 | 3169 |
3169 | 3170 |
3170 void StringCharFromCodeGenerator::GenerateSlow( | 3171 void StringCharFromCodeGenerator::GenerateSlow( |
3171 MacroAssembler* masm, | 3172 MacroAssembler* masm, |
3172 const RuntimeCallHelper& call_helper) { | 3173 const RuntimeCallHelper& call_helper) { |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3398 STATIC_ASSERT(kInternalizedTag == 0); | 3399 STATIC_ASSERT(kInternalizedTag == 0); |
3399 Label not_internalized_strings; | 3400 Label not_internalized_strings; |
3400 __ Orr(x12, lhs_type, rhs_type); | 3401 __ Orr(x12, lhs_type, rhs_type); |
3401 __ TestAndBranchIfAnySet( | 3402 __ TestAndBranchIfAnySet( |
3402 x12, kIsNotInternalizedMask, ¬_internalized_strings); | 3403 x12, kIsNotInternalizedMask, ¬_internalized_strings); |
3403 // Result is in rhs (x0), and not EQUAL, as rhs is not a smi. | 3404 // Result is in rhs (x0), and not EQUAL, as rhs is not a smi. |
3404 __ Ret(); | 3405 __ Ret(); |
3405 __ Bind(¬_internalized_strings); | 3406 __ Bind(¬_internalized_strings); |
3406 } | 3407 } |
3407 | 3408 |
3408 // Check that both strings are sequential ASCII. | 3409 // Check that both strings are sequential one-byte. |
3409 Label runtime; | 3410 Label runtime; |
3410 __ JumpIfBothInstanceTypesAreNotSequentialAscii( | 3411 __ JumpIfBothInstanceTypesAreNotSequentialOneByte(lhs_type, rhs_type, x12, |
3411 lhs_type, rhs_type, x12, x13, &runtime); | 3412 x13, &runtime); |
3412 | 3413 |
3413 // Compare flat ASCII strings. Returns when done. | 3414 // Compare flat one-byte strings. Returns when done. |
3414 if (equality) { | 3415 if (equality) { |
3415 StringHelper::GenerateFlatAsciiStringEquals(masm, lhs, rhs, x10, x11, x12); | 3416 StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, x10, x11, |
| 3417 x12); |
3416 } else { | 3418 } else { |
3417 StringHelper::GenerateCompareFlatAsciiStrings(masm, lhs, rhs, x10, x11, x12, | 3419 StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, x10, x11, |
3418 x13); | 3420 x12, x13); |
3419 } | 3421 } |
3420 | 3422 |
3421 // Handle more complex cases in runtime. | 3423 // Handle more complex cases in runtime. |
3422 __ Bind(&runtime); | 3424 __ Bind(&runtime); |
3423 __ Push(lhs, rhs); | 3425 __ Push(lhs, rhs); |
3424 if (equality) { | 3426 if (equality) { |
3425 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); | 3427 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
3426 } else { | 3428 } else { |
3427 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3429 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
3428 } | 3430 } |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3655 __ B(lt, ©_routine); | 3657 __ B(lt, ©_routine); |
3656 // Allocate new sliced string. At this point we do not reload the instance | 3658 // Allocate new sliced string. At this point we do not reload the instance |
3657 // type including the string encoding because we simply rely on the info | 3659 // type including the string encoding because we simply rely on the info |
3658 // provided by the original string. It does not matter if the original | 3660 // provided by the original string. It does not matter if the original |
3659 // string's encoding is wrong because we always have to recheck encoding of | 3661 // string's encoding is wrong because we always have to recheck encoding of |
3660 // the newly created string's parent anyway due to externalized strings. | 3662 // the newly created string's parent anyway due to externalized strings. |
3661 Label two_byte_slice, set_slice_header; | 3663 Label two_byte_slice, set_slice_header; |
3662 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | 3664 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); |
3663 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 3665 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
3664 __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_slice); | 3666 __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_slice); |
3665 __ AllocateAsciiSlicedString(result_string, result_length, x3, x4, | 3667 __ AllocateOneByteSlicedString(result_string, result_length, x3, x4, |
3666 &runtime); | 3668 &runtime); |
3667 __ B(&set_slice_header); | 3669 __ B(&set_slice_header); |
3668 | 3670 |
3669 __ Bind(&two_byte_slice); | 3671 __ Bind(&two_byte_slice); |
3670 __ AllocateTwoByteSlicedString(result_string, result_length, x3, x4, | 3672 __ AllocateTwoByteSlicedString(result_string, result_length, x3, x4, |
3671 &runtime); | 3673 &runtime); |
3672 | 3674 |
3673 __ Bind(&set_slice_header); | 3675 __ Bind(&set_slice_header); |
3674 __ SmiTag(from); | 3676 __ SmiTag(from); |
3675 __ Str(from, FieldMemOperand(result_string, SlicedString::kOffsetOffset)); | 3677 __ Str(from, FieldMemOperand(result_string, SlicedString::kOffsetOffset)); |
3676 __ Str(unpacked_string, | 3678 __ Str(unpacked_string, |
(...skipping 29 matching lines...) Expand all Loading... |
3706 // unpacked_char0 points to the first character of the underlying string. | 3708 // unpacked_char0 points to the first character of the underlying string. |
3707 __ B(&allocate_result); | 3709 __ B(&allocate_result); |
3708 | 3710 |
3709 __ Bind(&sequential_string); | 3711 __ Bind(&sequential_string); |
3710 // Locate first character of underlying subject string. | 3712 // Locate first character of underlying subject string. |
3711 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 3713 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
3712 __ Add(unpacked_char0, unpacked_string, | 3714 __ Add(unpacked_char0, unpacked_string, |
3713 SeqOneByteString::kHeaderSize - kHeapObjectTag); | 3715 SeqOneByteString::kHeaderSize - kHeapObjectTag); |
3714 | 3716 |
3715 __ Bind(&allocate_result); | 3717 __ Bind(&allocate_result); |
3716 // Sequential ASCII string. Allocate the result. | 3718 // Sequential one-byte string. Allocate the result. |
3717 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | 3719 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); |
3718 __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_sequential); | 3720 __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_sequential); |
3719 | 3721 |
3720 // Allocate and copy the resulting ASCII string. | 3722 // Allocate and copy the resulting one-byte string. |
3721 __ AllocateAsciiString(result_string, result_length, x3, x4, x5, &runtime); | 3723 __ AllocateOneByteString(result_string, result_length, x3, x4, x5, &runtime); |
3722 | 3724 |
3723 // Locate first character of substring to copy. | 3725 // Locate first character of substring to copy. |
3724 __ Add(substring_char0, unpacked_char0, from); | 3726 __ Add(substring_char0, unpacked_char0, from); |
3725 | 3727 |
3726 // Locate first character of result. | 3728 // Locate first character of result. |
3727 __ Add(result_char0, result_string, | 3729 __ Add(result_char0, result_string, |
3728 SeqOneByteString::kHeaderSize - kHeapObjectTag); | 3730 SeqOneByteString::kHeaderSize - kHeapObjectTag); |
3729 | 3731 |
3730 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 3732 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
3731 __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong); | 3733 __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3764 StringCharAtGenerator generator( | 3766 StringCharAtGenerator generator( |
3765 input_string, from, result_length, x0, | 3767 input_string, from, result_length, x0, |
3766 &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); | 3768 &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); |
3767 generator.GenerateFast(masm); | 3769 generator.GenerateFast(masm); |
3768 __ Drop(3); | 3770 __ Drop(3); |
3769 __ Ret(); | 3771 __ Ret(); |
3770 generator.SkipSlow(masm, &runtime); | 3772 generator.SkipSlow(masm, &runtime); |
3771 } | 3773 } |
3772 | 3774 |
3773 | 3775 |
3774 void StringHelper::GenerateFlatAsciiStringEquals(MacroAssembler* masm, | 3776 void StringHelper::GenerateFlatOneByteStringEquals( |
3775 Register left, Register right, | 3777 MacroAssembler* masm, Register left, Register right, Register scratch1, |
3776 Register scratch1, | 3778 Register scratch2, Register scratch3) { |
3777 Register scratch2, | |
3778 Register scratch3) { | |
3779 DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3)); | 3779 DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3)); |
3780 Register result = x0; | 3780 Register result = x0; |
3781 Register left_length = scratch1; | 3781 Register left_length = scratch1; |
3782 Register right_length = scratch2; | 3782 Register right_length = scratch2; |
3783 | 3783 |
3784 // Compare lengths. If lengths differ, strings can't be equal. Lengths are | 3784 // Compare lengths. If lengths differ, strings can't be equal. Lengths are |
3785 // smis, and don't need to be untagged. | 3785 // smis, and don't need to be untagged. |
3786 Label strings_not_equal, check_zero_length; | 3786 Label strings_not_equal, check_zero_length; |
3787 __ Ldr(left_length, FieldMemOperand(left, String::kLengthOffset)); | 3787 __ Ldr(left_length, FieldMemOperand(left, String::kLengthOffset)); |
3788 __ Ldr(right_length, FieldMemOperand(right, String::kLengthOffset)); | 3788 __ Ldr(right_length, FieldMemOperand(right, String::kLengthOffset)); |
3789 __ Cmp(left_length, right_length); | 3789 __ Cmp(left_length, right_length); |
3790 __ B(eq, &check_zero_length); | 3790 __ B(eq, &check_zero_length); |
3791 | 3791 |
3792 __ Bind(&strings_not_equal); | 3792 __ Bind(&strings_not_equal); |
3793 __ Mov(result, Smi::FromInt(NOT_EQUAL)); | 3793 __ Mov(result, Smi::FromInt(NOT_EQUAL)); |
3794 __ Ret(); | 3794 __ Ret(); |
3795 | 3795 |
3796 // Check if the length is zero. If so, the strings must be equal (and empty.) | 3796 // Check if the length is zero. If so, the strings must be equal (and empty.) |
3797 Label compare_chars; | 3797 Label compare_chars; |
3798 __ Bind(&check_zero_length); | 3798 __ Bind(&check_zero_length); |
3799 STATIC_ASSERT(kSmiTag == 0); | 3799 STATIC_ASSERT(kSmiTag == 0); |
3800 __ Cbnz(left_length, &compare_chars); | 3800 __ Cbnz(left_length, &compare_chars); |
3801 __ Mov(result, Smi::FromInt(EQUAL)); | 3801 __ Mov(result, Smi::FromInt(EQUAL)); |
3802 __ Ret(); | 3802 __ Ret(); |
3803 | 3803 |
3804 // Compare characters. Falls through if all characters are equal. | 3804 // Compare characters. Falls through if all characters are equal. |
3805 __ Bind(&compare_chars); | 3805 __ Bind(&compare_chars); |
3806 GenerateAsciiCharsCompareLoop(masm, left, right, left_length, scratch2, | 3806 GenerateOneByteCharsCompareLoop(masm, left, right, left_length, scratch2, |
3807 scratch3, &strings_not_equal); | 3807 scratch3, &strings_not_equal); |
3808 | 3808 |
3809 // Characters in strings are equal. | 3809 // Characters in strings are equal. |
3810 __ Mov(result, Smi::FromInt(EQUAL)); | 3810 __ Mov(result, Smi::FromInt(EQUAL)); |
3811 __ Ret(); | 3811 __ Ret(); |
3812 } | 3812 } |
3813 | 3813 |
3814 | 3814 |
3815 void StringHelper::GenerateCompareFlatAsciiStrings( | 3815 void StringHelper::GenerateCompareFlatOneByteStrings( |
3816 MacroAssembler* masm, Register left, Register right, Register scratch1, | 3816 MacroAssembler* masm, Register left, Register right, Register scratch1, |
3817 Register scratch2, Register scratch3, Register scratch4) { | 3817 Register scratch2, Register scratch3, Register scratch4) { |
3818 DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3, scratch4)); | 3818 DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3, scratch4)); |
3819 Label result_not_equal, compare_lengths; | 3819 Label result_not_equal, compare_lengths; |
3820 | 3820 |
3821 // Find minimum length and length difference. | 3821 // Find minimum length and length difference. |
3822 Register length_delta = scratch3; | 3822 Register length_delta = scratch3; |
3823 __ Ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); | 3823 __ Ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); |
3824 __ Ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); | 3824 __ Ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
3825 __ Subs(length_delta, scratch1, scratch2); | 3825 __ Subs(length_delta, scratch1, scratch2); |
3826 | 3826 |
3827 Register min_length = scratch1; | 3827 Register min_length = scratch1; |
3828 __ Csel(min_length, scratch2, scratch1, gt); | 3828 __ Csel(min_length, scratch2, scratch1, gt); |
3829 __ Cbz(min_length, &compare_lengths); | 3829 __ Cbz(min_length, &compare_lengths); |
3830 | 3830 |
3831 // Compare loop. | 3831 // Compare loop. |
3832 GenerateAsciiCharsCompareLoop(masm, | 3832 GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2, |
3833 left, right, min_length, scratch2, scratch4, | 3833 scratch4, &result_not_equal); |
3834 &result_not_equal); | |
3835 | 3834 |
3836 // Compare lengths - strings up to min-length are equal. | 3835 // Compare lengths - strings up to min-length are equal. |
3837 __ Bind(&compare_lengths); | 3836 __ Bind(&compare_lengths); |
3838 | 3837 |
3839 DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); | 3838 DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); |
3840 | 3839 |
3841 // Use length_delta as result if it's zero. | 3840 // Use length_delta as result if it's zero. |
3842 Register result = x0; | 3841 Register result = x0; |
3843 __ Subs(result, length_delta, 0); | 3842 __ Subs(result, length_delta, 0); |
3844 | 3843 |
3845 __ Bind(&result_not_equal); | 3844 __ Bind(&result_not_equal); |
3846 Register greater = x10; | 3845 Register greater = x10; |
3847 Register less = x11; | 3846 Register less = x11; |
3848 __ Mov(greater, Smi::FromInt(GREATER)); | 3847 __ Mov(greater, Smi::FromInt(GREATER)); |
3849 __ Mov(less, Smi::FromInt(LESS)); | 3848 __ Mov(less, Smi::FromInt(LESS)); |
3850 __ CmovX(result, greater, gt); | 3849 __ CmovX(result, greater, gt); |
3851 __ CmovX(result, less, lt); | 3850 __ CmovX(result, less, lt); |
3852 __ Ret(); | 3851 __ Ret(); |
3853 } | 3852 } |
3854 | 3853 |
3855 | 3854 |
3856 void StringHelper::GenerateAsciiCharsCompareLoop( | 3855 void StringHelper::GenerateOneByteCharsCompareLoop( |
3857 MacroAssembler* masm, Register left, Register right, Register length, | 3856 MacroAssembler* masm, Register left, Register right, Register length, |
3858 Register scratch1, Register scratch2, Label* chars_not_equal) { | 3857 Register scratch1, Register scratch2, Label* chars_not_equal) { |
3859 DCHECK(!AreAliased(left, right, length, scratch1, scratch2)); | 3858 DCHECK(!AreAliased(left, right, length, scratch1, scratch2)); |
3860 | 3859 |
3861 // Change index to run from -length to -1 by adding length to string | 3860 // Change index to run from -length to -1 by adding length to string |
3862 // start. This means that loop ends when index reaches zero, which | 3861 // start. This means that loop ends when index reaches zero, which |
3863 // doesn't need an additional compare. | 3862 // doesn't need an additional compare. |
3864 __ SmiUntag(length); | 3863 __ SmiUntag(length); |
3865 __ Add(scratch1, length, SeqOneByteString::kHeaderSize - kHeapObjectTag); | 3864 __ Add(scratch1, length, SeqOneByteString::kHeaderSize - kHeapObjectTag); |
3866 __ Add(left, left, scratch1); | 3865 __ Add(left, left, scratch1); |
(...skipping 29 matching lines...) Expand all Loading... |
3896 | 3895 |
3897 Label not_same; | 3896 Label not_same; |
3898 __ Subs(result, right, left); | 3897 __ Subs(result, right, left); |
3899 __ B(ne, ¬_same); | 3898 __ B(ne, ¬_same); |
3900 STATIC_ASSERT(EQUAL == 0); | 3899 STATIC_ASSERT(EQUAL == 0); |
3901 __ IncrementCounter(counters->string_compare_native(), 1, x3, x4); | 3900 __ IncrementCounter(counters->string_compare_native(), 1, x3, x4); |
3902 __ Ret(); | 3901 __ Ret(); |
3903 | 3902 |
3904 __ Bind(¬_same); | 3903 __ Bind(¬_same); |
3905 | 3904 |
3906 // Check that both objects are sequential ASCII strings. | 3905 // Check that both objects are sequential one-byte strings. |
3907 __ JumpIfEitherIsNotSequentialAsciiStrings(left, right, x12, x13, &runtime); | 3906 __ JumpIfEitherIsNotSequentialOneByteStrings(left, right, x12, x13, &runtime); |
3908 | 3907 |
3909 // Compare flat ASCII strings natively. Remove arguments from stack first, | 3908 // Compare flat one-byte strings natively. Remove arguments from stack first, |
3910 // as this function will generate a return. | 3909 // as this function will generate a return. |
3911 __ IncrementCounter(counters->string_compare_native(), 1, x3, x4); | 3910 __ IncrementCounter(counters->string_compare_native(), 1, x3, x4); |
3912 StringHelper::GenerateCompareFlatAsciiStrings(masm, left, right, x12, x13, | 3911 StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, x12, x13, |
3913 x14, x15); | 3912 x14, x15); |
3914 | 3913 |
3915 __ Bind(&runtime); | 3914 __ Bind(&runtime); |
3916 | 3915 |
3917 // Push arguments back on to the stack. | 3916 // Push arguments back on to the stack. |
3918 // sp[0] = right string | 3917 // sp[0] = right string |
3919 // sp[8] = left string. | 3918 // sp[8] = left string. |
3920 __ Push(left, right); | 3919 __ Push(left, right); |
3921 | 3920 |
3922 // Call the runtime. | 3921 // Call the runtime. |
3923 // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer. | 3922 // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer. |
(...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5041 MemOperand(fp, 6 * kPointerSize), | 5040 MemOperand(fp, 6 * kPointerSize), |
5042 NULL); | 5041 NULL); |
5043 } | 5042 } |
5044 | 5043 |
5045 | 5044 |
5046 #undef __ | 5045 #undef __ |
5047 | 5046 |
5048 } } // namespace v8::internal | 5047 } } // namespace v8::internal |
5049 | 5048 |
5050 #endif // V8_TARGET_ARCH_ARM64 | 5049 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |