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