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_X64 | 7 #if V8_TARGET_ARCH_X64 |
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 1062 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1073 // (5b) Is subject external? If yes, go to (8). | 1073 // (5b) Is subject external? If yes, go to (8). |
1074 __ testb(rbx, Immediate(kStringRepresentationMask)); | 1074 __ testb(rbx, Immediate(kStringRepresentationMask)); |
1075 // The underlying external string is never a short external string. | 1075 // The underlying external string is never a short external string. |
1076 STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength); | 1076 STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength); |
1077 STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength); | 1077 STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength); |
1078 __ j(not_zero, &external_string); // Go to (8) | 1078 __ j(not_zero, &external_string); // Go to (8) |
1079 | 1079 |
1080 // (6) One byte sequential. Load regexp code for one byte. | 1080 // (6) One byte sequential. Load regexp code for one byte. |
1081 __ bind(&seq_one_byte_string); | 1081 __ bind(&seq_one_byte_string); |
1082 // rax: RegExp data (FixedArray) | 1082 // rax: RegExp data (FixedArray) |
1083 __ movp(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); | 1083 __ movp(r11, FieldOperand(rax, JSRegExp::kDataOneByteCodeOffset)); |
1084 __ Set(rcx, 1); // Type is one byte. | 1084 __ Set(rcx, 1); // Type is one byte. |
1085 | 1085 |
1086 // (E) Carry on. String handling is done. | 1086 // (E) Carry on. String handling is done. |
1087 __ bind(&check_code); | 1087 __ bind(&check_code); |
1088 // r11: irregexp code | 1088 // r11: irregexp code |
1089 // Check that the irregexp code has been generated for the actual string | 1089 // Check that the irregexp code has been generated for the actual string |
1090 // encoding. If it has, the field contains a code object otherwise it contains | 1090 // encoding. If it has, the field contains a code object otherwise it contains |
1091 // smi (code flushing support) | 1091 // smi (code flushing support) |
1092 __ JumpIfSmi(r11, &runtime); | 1092 __ JumpIfSmi(r11, &runtime); |
1093 | 1093 |
1094 // rdi: sequential subject string (or look-alike, external string) | 1094 // rdi: sequential subject string (or look-alike, external string) |
1095 // r15: original subject string | 1095 // r15: original subject string |
1096 // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); | 1096 // rcx: encoding of subject string (1 if one_byte, 0 if two_byte); |
1097 // r11: code | 1097 // r11: code |
1098 // Load used arguments before starting to push arguments for call to native | 1098 // Load used arguments before starting to push arguments for call to native |
1099 // RegExp code to avoid handling changing stack height. | 1099 // RegExp code to avoid handling changing stack height. |
1100 // We have to use r15 instead of rdi to load the length because rdi might | 1100 // We have to use r15 instead of rdi to load the length because rdi might |
1101 // have been only made to look like a sequential string when it actually | 1101 // have been only made to look like a sequential string when it actually |
1102 // is an external string. | 1102 // is an external string. |
1103 __ movp(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX)); | 1103 __ movp(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX)); |
1104 __ JumpIfNotSmi(rbx, &runtime); | 1104 __ JumpIfNotSmi(rbx, &runtime); |
1105 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); | 1105 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); |
1106 __ j(above_equal, &runtime); | 1106 __ j(above_equal, &runtime); |
1107 __ SmiToInteger64(rbx, rbx); | 1107 __ SmiToInteger64(rbx, rbx); |
1108 | 1108 |
1109 // rdi: subject string | 1109 // rdi: subject string |
1110 // rbx: previous index | 1110 // rbx: previous index |
1111 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); | 1111 // rcx: encoding of subject string (1 if one_byte 0 if two_byte); |
1112 // r11: code | 1112 // r11: code |
1113 // All checks done. Now push arguments for native regexp code. | 1113 // All checks done. Now push arguments for native regexp code. |
1114 Counters* counters = isolate()->counters(); | 1114 Counters* counters = isolate()->counters(); |
1115 __ IncrementCounter(counters->regexp_entry_native(), 1); | 1115 __ IncrementCounter(counters->regexp_entry_native(), 1); |
1116 | 1116 |
1117 // Isolates: note we add an additional parameter here (isolate pointer). | 1117 // Isolates: note we add an additional parameter here (isolate pointer). |
1118 static const int kRegExpExecuteArguments = 9; | 1118 static const int kRegExpExecuteArguments = 9; |
1119 int argument_slots_on_stack = | 1119 int argument_slots_on_stack = |
1120 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); | 1120 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); |
1121 __ EnterApiExitFrame(argument_slots_on_stack); | 1121 __ EnterApiExitFrame(argument_slots_on_stack); |
(...skipping 28 matching lines...) Expand all Loading... |
1150 // Argument 5: static offsets vector buffer. | 1150 // Argument 5: static offsets vector buffer. |
1151 __ LoadAddress( | 1151 __ LoadAddress( |
1152 r8, ExternalReference::address_of_static_offsets_vector(isolate())); | 1152 r8, ExternalReference::address_of_static_offsets_vector(isolate())); |
1153 // Argument 5 passed in r8 on Linux and on the stack on Windows. | 1153 // Argument 5 passed in r8 on Linux and on the stack on Windows. |
1154 #ifdef _WIN64 | 1154 #ifdef _WIN64 |
1155 __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r8); | 1155 __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r8); |
1156 #endif | 1156 #endif |
1157 | 1157 |
1158 // rdi: subject string | 1158 // rdi: subject string |
1159 // rbx: previous index | 1159 // rbx: previous index |
1160 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); | 1160 // rcx: encoding of subject string (1 if one_byte 0 if two_byte); |
1161 // r11: code | 1161 // r11: code |
1162 // r14: slice offset | 1162 // r14: slice offset |
1163 // r15: original subject string | 1163 // r15: original subject string |
1164 | 1164 |
1165 // Argument 2: Previous index. | 1165 // Argument 2: Previous index. |
1166 __ movp(arg_reg_2, rbx); | 1166 __ movp(arg_reg_2, rbx); |
1167 | 1167 |
1168 // Argument 4: End of string data | 1168 // Argument 4: End of string data |
1169 // Argument 3: Start of string data | 1169 // Argument 3: Start of string data |
1170 Label setup_two_byte, setup_rest, got_length, length_not_from_slice; | 1170 Label setup_two_byte, setup_rest, got_length, length_not_from_slice; |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1590 masm, &check_for_strings, rdx, kScratchRegister); | 1590 masm, &check_for_strings, rdx, kScratchRegister); |
1591 | 1591 |
1592 // We've already checked for object identity, so if both operands are | 1592 // We've already checked for object identity, so if both operands are |
1593 // internalized strings they aren't equal. Register rax (not rax) already | 1593 // internalized strings they aren't equal. Register rax (not rax) already |
1594 // holds a non-zero value, which indicates not equal, so just return. | 1594 // holds a non-zero value, which indicates not equal, so just return. |
1595 __ ret(0); | 1595 __ ret(0); |
1596 } | 1596 } |
1597 | 1597 |
1598 __ bind(&check_for_strings); | 1598 __ bind(&check_for_strings); |
1599 | 1599 |
1600 __ JumpIfNotBothSequentialAsciiStrings( | 1600 __ JumpIfNotBothSequentialOneByteStrings(rdx, rax, rcx, rbx, |
1601 rdx, rax, rcx, rbx, &check_unequal_objects); | 1601 &check_unequal_objects); |
1602 | 1602 |
1603 // Inline comparison of ASCII strings. | 1603 // Inline comparison of one-byte strings. |
1604 if (cc == equal) { | 1604 if (cc == equal) { |
1605 StringHelper::GenerateFlatAsciiStringEquals(masm, rdx, rax, rcx, rbx); | 1605 StringHelper::GenerateFlatOneByteStringEquals(masm, rdx, rax, rcx, rbx); |
1606 } else { | 1606 } else { |
1607 StringHelper::GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, | 1607 StringHelper::GenerateCompareFlatOneByteStrings(masm, rdx, rax, rcx, rbx, |
1608 r8); | 1608 rdi, r8); |
1609 } | 1609 } |
1610 | 1610 |
1611 #ifdef DEBUG | 1611 #ifdef DEBUG |
1612 __ Abort(kUnexpectedFallThroughFromStringComparison); | 1612 __ Abort(kUnexpectedFallThroughFromStringComparison); |
1613 #endif | 1613 #endif |
1614 | 1614 |
1615 __ bind(&check_unequal_objects); | 1615 __ bind(&check_unequal_objects); |
1616 if (cc == equal && !strict()) { | 1616 if (cc == equal && !strict()) { |
1617 // Not strict equality. Objects are unequal if | 1617 // Not strict equality. Objects are unequal if |
1618 // they are both JSObjects and not undetectable, | 1618 // they are both JSObjects and not undetectable, |
(...skipping 1048 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2667 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * | 2667 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * |
2668 kPointerSize); | 2668 kPointerSize); |
2669 } | 2669 } |
2670 } | 2670 } |
2671 | 2671 |
2672 | 2672 |
2673 // ------------------------------------------------------------------------- | 2673 // ------------------------------------------------------------------------- |
2674 // StringCharCodeAtGenerator | 2674 // StringCharCodeAtGenerator |
2675 | 2675 |
2676 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 2676 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
2677 Label flat_string; | |
2678 Label ascii_string; | |
2679 Label got_char_code; | |
2680 Label sliced_string; | |
2681 | |
2682 // If the receiver is a smi trigger the non-string case. | 2677 // If the receiver is a smi trigger the non-string case. |
2683 __ JumpIfSmi(object_, receiver_not_string_); | 2678 __ JumpIfSmi(object_, receiver_not_string_); |
2684 | 2679 |
2685 // Fetch the instance type of the receiver into result register. | 2680 // Fetch the instance type of the receiver into result register. |
2686 __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 2681 __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
2687 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 2682 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
2688 // If the receiver is not a string trigger the non-string case. | 2683 // If the receiver is not a string trigger the non-string case. |
2689 __ testb(result_, Immediate(kIsNotStringMask)); | 2684 __ testb(result_, Immediate(kIsNotStringMask)); |
2690 __ j(not_zero, receiver_not_string_); | 2685 __ j(not_zero, receiver_not_string_); |
2691 | 2686 |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2940 // Allocate new sliced string. At this point we do not reload the instance | 2935 // Allocate new sliced string. At this point we do not reload the instance |
2941 // type including the string encoding because we simply rely on the info | 2936 // type including the string encoding because we simply rely on the info |
2942 // provided by the original string. It does not matter if the original | 2937 // provided by the original string. It does not matter if the original |
2943 // string's encoding is wrong because we always have to recheck encoding of | 2938 // string's encoding is wrong because we always have to recheck encoding of |
2944 // the newly created string's parent anyways due to externalized strings. | 2939 // the newly created string's parent anyways due to externalized strings. |
2945 Label two_byte_slice, set_slice_header; | 2940 Label two_byte_slice, set_slice_header; |
2946 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | 2941 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); |
2947 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 2942 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
2948 __ testb(rbx, Immediate(kStringEncodingMask)); | 2943 __ testb(rbx, Immediate(kStringEncodingMask)); |
2949 __ j(zero, &two_byte_slice, Label::kNear); | 2944 __ j(zero, &two_byte_slice, Label::kNear); |
2950 __ AllocateAsciiSlicedString(rax, rbx, r14, &runtime); | 2945 __ AllocateOneByteSlicedString(rax, rbx, r14, &runtime); |
2951 __ jmp(&set_slice_header, Label::kNear); | 2946 __ jmp(&set_slice_header, Label::kNear); |
2952 __ bind(&two_byte_slice); | 2947 __ bind(&two_byte_slice); |
2953 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); | 2948 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); |
2954 __ bind(&set_slice_header); | 2949 __ bind(&set_slice_header); |
2955 __ Integer32ToSmi(rcx, rcx); | 2950 __ Integer32ToSmi(rcx, rcx); |
2956 __ movp(FieldOperand(rax, SlicedString::kLengthOffset), rcx); | 2951 __ movp(FieldOperand(rax, SlicedString::kLengthOffset), rcx); |
2957 __ movp(FieldOperand(rax, SlicedString::kHashFieldOffset), | 2952 __ movp(FieldOperand(rax, SlicedString::kHashFieldOffset), |
2958 Immediate(String::kEmptyHashField)); | 2953 Immediate(String::kEmptyHashField)); |
2959 __ movp(FieldOperand(rax, SlicedString::kParentOffset), rdi); | 2954 __ movp(FieldOperand(rax, SlicedString::kParentOffset), rdi); |
2960 __ movp(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); | 2955 __ movp(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); |
(...skipping 24 matching lines...) Expand all Loading... |
2985 // Move the pointer so that offset-wise, it looks like a sequential string. | 2980 // Move the pointer so that offset-wise, it looks like a sequential string. |
2986 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 2981 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
2987 __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 2982 __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
2988 | 2983 |
2989 __ bind(&sequential_string); | 2984 __ bind(&sequential_string); |
2990 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | 2985 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); |
2991 __ testb(rbx, Immediate(kStringEncodingMask)); | 2986 __ testb(rbx, Immediate(kStringEncodingMask)); |
2992 __ j(zero, &two_byte_sequential); | 2987 __ j(zero, &two_byte_sequential); |
2993 | 2988 |
2994 // Allocate the result. | 2989 // Allocate the result. |
2995 __ AllocateAsciiString(rax, rcx, r11, r14, r15, &runtime); | 2990 __ AllocateOneByteString(rax, rcx, r11, r14, r15, &runtime); |
2996 | 2991 |
2997 // rax: result string | 2992 // rax: result string |
2998 // rcx: result string length | 2993 // rcx: result string length |
2999 { // Locate character of sub string start. | 2994 { // Locate character of sub string start. |
3000 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); | 2995 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); |
3001 __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale, | 2996 __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale, |
3002 SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 2997 SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
3003 } | 2998 } |
3004 // Locate first character of result. | 2999 // Locate first character of result. |
3005 __ leap(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | 3000 __ leap(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3046 // rcx: sub string length (smi) | 3041 // rcx: sub string length (smi) |
3047 // rdx: from index (smi) | 3042 // rdx: from index (smi) |
3048 StringCharAtGenerator generator( | 3043 StringCharAtGenerator generator( |
3049 rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); | 3044 rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); |
3050 generator.GenerateFast(masm); | 3045 generator.GenerateFast(masm); |
3051 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | 3046 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
3052 generator.SkipSlow(masm, &runtime); | 3047 generator.SkipSlow(masm, &runtime); |
3053 } | 3048 } |
3054 | 3049 |
3055 | 3050 |
3056 void StringHelper::GenerateFlatAsciiStringEquals(MacroAssembler* masm, | 3051 void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm, |
3057 Register left, Register right, | 3052 Register left, |
3058 Register scratch1, | 3053 Register right, |
3059 Register scratch2) { | 3054 Register scratch1, |
| 3055 Register scratch2) { |
3060 Register length = scratch1; | 3056 Register length = scratch1; |
3061 | 3057 |
3062 // Compare lengths. | 3058 // Compare lengths. |
3063 Label check_zero_length; | 3059 Label check_zero_length; |
3064 __ movp(length, FieldOperand(left, String::kLengthOffset)); | 3060 __ movp(length, FieldOperand(left, String::kLengthOffset)); |
3065 __ SmiCompare(length, FieldOperand(right, String::kLengthOffset)); | 3061 __ SmiCompare(length, FieldOperand(right, String::kLengthOffset)); |
3066 __ j(equal, &check_zero_length, Label::kNear); | 3062 __ j(equal, &check_zero_length, Label::kNear); |
3067 __ Move(rax, Smi::FromInt(NOT_EQUAL)); | 3063 __ Move(rax, Smi::FromInt(NOT_EQUAL)); |
3068 __ ret(0); | 3064 __ ret(0); |
3069 | 3065 |
3070 // Check if the length is zero. | 3066 // Check if the length is zero. |
3071 Label compare_chars; | 3067 Label compare_chars; |
3072 __ bind(&check_zero_length); | 3068 __ bind(&check_zero_length); |
3073 STATIC_ASSERT(kSmiTag == 0); | 3069 STATIC_ASSERT(kSmiTag == 0); |
3074 __ SmiTest(length); | 3070 __ SmiTest(length); |
3075 __ j(not_zero, &compare_chars, Label::kNear); | 3071 __ j(not_zero, &compare_chars, Label::kNear); |
3076 __ Move(rax, Smi::FromInt(EQUAL)); | 3072 __ Move(rax, Smi::FromInt(EQUAL)); |
3077 __ ret(0); | 3073 __ ret(0); |
3078 | 3074 |
3079 // Compare characters. | 3075 // Compare characters. |
3080 __ bind(&compare_chars); | 3076 __ bind(&compare_chars); |
3081 Label strings_not_equal; | 3077 Label strings_not_equal; |
3082 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, | 3078 GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2, |
3083 &strings_not_equal, Label::kNear); | 3079 &strings_not_equal, Label::kNear); |
3084 | 3080 |
3085 // Characters are equal. | 3081 // Characters are equal. |
3086 __ Move(rax, Smi::FromInt(EQUAL)); | 3082 __ Move(rax, Smi::FromInt(EQUAL)); |
3087 __ ret(0); | 3083 __ ret(0); |
3088 | 3084 |
3089 // Characters are not equal. | 3085 // Characters are not equal. |
3090 __ bind(&strings_not_equal); | 3086 __ bind(&strings_not_equal); |
3091 __ Move(rax, Smi::FromInt(NOT_EQUAL)); | 3087 __ Move(rax, Smi::FromInt(NOT_EQUAL)); |
3092 __ ret(0); | 3088 __ ret(0); |
3093 } | 3089 } |
3094 | 3090 |
3095 | 3091 |
3096 void StringHelper::GenerateCompareFlatAsciiStrings( | 3092 void StringHelper::GenerateCompareFlatOneByteStrings( |
3097 MacroAssembler* masm, Register left, Register right, Register scratch1, | 3093 MacroAssembler* masm, Register left, Register right, Register scratch1, |
3098 Register scratch2, Register scratch3, Register scratch4) { | 3094 Register scratch2, Register scratch3, Register scratch4) { |
3099 // Ensure that you can always subtract a string length from a non-negative | 3095 // Ensure that you can always subtract a string length from a non-negative |
3100 // number (e.g. another length). | 3096 // number (e.g. another length). |
3101 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); | 3097 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); |
3102 | 3098 |
3103 // Find minimum length and length difference. | 3099 // Find minimum length and length difference. |
3104 __ movp(scratch1, FieldOperand(left, String::kLengthOffset)); | 3100 __ movp(scratch1, FieldOperand(left, String::kLengthOffset)); |
3105 __ movp(scratch4, scratch1); | 3101 __ movp(scratch4, scratch1); |
3106 __ SmiSub(scratch4, | 3102 __ SmiSub(scratch4, |
(...skipping 11 matching lines...) Expand all Loading... |
3118 // Register scratch1 now holds Min(left.length, right.length). | 3114 // Register scratch1 now holds Min(left.length, right.length). |
3119 const Register min_length = scratch1; | 3115 const Register min_length = scratch1; |
3120 | 3116 |
3121 Label compare_lengths; | 3117 Label compare_lengths; |
3122 // If min-length is zero, go directly to comparing lengths. | 3118 // If min-length is zero, go directly to comparing lengths. |
3123 __ SmiTest(min_length); | 3119 __ SmiTest(min_length); |
3124 __ j(zero, &compare_lengths, Label::kNear); | 3120 __ j(zero, &compare_lengths, Label::kNear); |
3125 | 3121 |
3126 // Compare loop. | 3122 // Compare loop. |
3127 Label result_not_equal; | 3123 Label result_not_equal; |
3128 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, | 3124 GenerateOneByteCharsCompareLoop( |
3129 &result_not_equal, | 3125 masm, left, right, min_length, scratch2, &result_not_equal, |
3130 // In debug-code mode, SmiTest below might push | 3126 // In debug-code mode, SmiTest below might push |
3131 // the target label outside the near range. | 3127 // the target label outside the near range. |
3132 Label::kFar); | 3128 Label::kFar); |
3133 | 3129 |
3134 // Completed loop without finding different characters. | 3130 // Completed loop without finding different characters. |
3135 // Compare lengths (precomputed). | 3131 // Compare lengths (precomputed). |
3136 __ bind(&compare_lengths); | 3132 __ bind(&compare_lengths); |
3137 __ SmiTest(length_difference); | 3133 __ SmiTest(length_difference); |
3138 Label length_not_equal; | 3134 Label length_not_equal; |
3139 __ j(not_zero, &length_not_equal, Label::kNear); | 3135 __ j(not_zero, &length_not_equal, Label::kNear); |
3140 | 3136 |
3141 // Result is EQUAL. | 3137 // Result is EQUAL. |
3142 __ Move(rax, Smi::FromInt(EQUAL)); | 3138 __ Move(rax, Smi::FromInt(EQUAL)); |
(...skipping 13 matching lines...) Expand all Loading... |
3156 __ Move(rax, Smi::FromInt(LESS)); | 3152 __ Move(rax, Smi::FromInt(LESS)); |
3157 __ ret(0); | 3153 __ ret(0); |
3158 | 3154 |
3159 // Result is GREATER. | 3155 // Result is GREATER. |
3160 __ bind(&result_greater); | 3156 __ bind(&result_greater); |
3161 __ Move(rax, Smi::FromInt(GREATER)); | 3157 __ Move(rax, Smi::FromInt(GREATER)); |
3162 __ ret(0); | 3158 __ ret(0); |
3163 } | 3159 } |
3164 | 3160 |
3165 | 3161 |
3166 void StringHelper::GenerateAsciiCharsCompareLoop( | 3162 void StringHelper::GenerateOneByteCharsCompareLoop( |
3167 MacroAssembler* masm, Register left, Register right, Register length, | 3163 MacroAssembler* masm, Register left, Register right, Register length, |
3168 Register scratch, Label* chars_not_equal, Label::Distance near_jump) { | 3164 Register scratch, Label* chars_not_equal, Label::Distance near_jump) { |
3169 // Change index to run from -length to -1 by adding length to string | 3165 // Change index to run from -length to -1 by adding length to string |
3170 // start. This means that loop ends when index reaches zero, which | 3166 // start. This means that loop ends when index reaches zero, which |
3171 // doesn't need an additional compare. | 3167 // doesn't need an additional compare. |
3172 __ SmiToInteger32(length, length); | 3168 __ SmiToInteger32(length, length); |
3173 __ leap(left, | 3169 __ leap(left, |
3174 FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize)); | 3170 FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize)); |
3175 __ leap(right, | 3171 __ leap(right, |
3176 FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize)); | 3172 FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize)); |
(...skipping 27 matching lines...) Expand all Loading... |
3204 Label not_same; | 3200 Label not_same; |
3205 __ cmpp(rdx, rax); | 3201 __ cmpp(rdx, rax); |
3206 __ j(not_equal, ¬_same, Label::kNear); | 3202 __ j(not_equal, ¬_same, Label::kNear); |
3207 __ Move(rax, Smi::FromInt(EQUAL)); | 3203 __ Move(rax, Smi::FromInt(EQUAL)); |
3208 Counters* counters = isolate()->counters(); | 3204 Counters* counters = isolate()->counters(); |
3209 __ IncrementCounter(counters->string_compare_native(), 1); | 3205 __ IncrementCounter(counters->string_compare_native(), 1); |
3210 __ ret(2 * kPointerSize); | 3206 __ ret(2 * kPointerSize); |
3211 | 3207 |
3212 __ bind(¬_same); | 3208 __ bind(¬_same); |
3213 | 3209 |
3214 // Check that both are sequential ASCII strings. | 3210 // Check that both are sequential one-byte strings. |
3215 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); | 3211 __ JumpIfNotBothSequentialOneByteStrings(rdx, rax, rcx, rbx, &runtime); |
3216 | 3212 |
3217 // Inline comparison of ASCII strings. | 3213 // Inline comparison of one-byte strings. |
3218 __ IncrementCounter(counters->string_compare_native(), 1); | 3214 __ IncrementCounter(counters->string_compare_native(), 1); |
3219 // Drop arguments from the stack | 3215 // Drop arguments from the stack |
3220 __ PopReturnAddressTo(rcx); | 3216 __ PopReturnAddressTo(rcx); |
3221 __ addp(rsp, Immediate(2 * kPointerSize)); | 3217 __ addp(rsp, Immediate(2 * kPointerSize)); |
3222 __ PushReturnAddressFrom(rcx); | 3218 __ PushReturnAddressFrom(rcx); |
3223 StringHelper::GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, | 3219 StringHelper::GenerateCompareFlatOneByteStrings(masm, rdx, rax, rcx, rbx, rdi, |
3224 r8); | 3220 r8); |
3225 | 3221 |
3226 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 3222 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
3227 // tagged as a small integer. | 3223 // tagged as a small integer. |
3228 __ bind(&runtime); | 3224 __ bind(&runtime); |
3229 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3225 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
3230 } | 3226 } |
3231 | 3227 |
3232 | 3228 |
3233 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { | 3229 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { |
3234 // ----------- S t a t e ------------- | 3230 // ----------- S t a t e ------------- |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3495 __ orp(tmp1, tmp2); | 3491 __ orp(tmp1, tmp2); |
3496 __ testb(tmp1, Immediate(kIsNotInternalizedMask)); | 3492 __ testb(tmp1, Immediate(kIsNotInternalizedMask)); |
3497 __ j(not_zero, &do_compare, Label::kNear); | 3493 __ j(not_zero, &do_compare, Label::kNear); |
3498 // Make sure rax is non-zero. At this point input operands are | 3494 // Make sure rax is non-zero. At this point input operands are |
3499 // guaranteed to be non-zero. | 3495 // guaranteed to be non-zero. |
3500 DCHECK(right.is(rax)); | 3496 DCHECK(right.is(rax)); |
3501 __ ret(0); | 3497 __ ret(0); |
3502 __ bind(&do_compare); | 3498 __ bind(&do_compare); |
3503 } | 3499 } |
3504 | 3500 |
3505 // Check that both strings are sequential ASCII. | 3501 // Check that both strings are sequential one-byte. |
3506 Label runtime; | 3502 Label runtime; |
3507 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); | 3503 __ JumpIfNotBothSequentialOneByteStrings(left, right, tmp1, tmp2, &runtime); |
3508 | 3504 |
3509 // Compare flat ASCII strings. Returns when done. | 3505 // Compare flat one-byte strings. Returns when done. |
3510 if (equality) { | 3506 if (equality) { |
3511 StringHelper::GenerateFlatAsciiStringEquals(masm, left, right, tmp1, tmp2); | 3507 StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1, |
| 3508 tmp2); |
3512 } else { | 3509 } else { |
3513 StringHelper::GenerateCompareFlatAsciiStrings(masm, left, right, tmp1, tmp2, | 3510 StringHelper::GenerateCompareFlatOneByteStrings( |
3514 tmp3, kScratchRegister); | 3511 masm, left, right, tmp1, tmp2, tmp3, kScratchRegister); |
3515 } | 3512 } |
3516 | 3513 |
3517 // Handle more complex cases in runtime. | 3514 // Handle more complex cases in runtime. |
3518 __ bind(&runtime); | 3515 __ bind(&runtime); |
3519 __ PopReturnAddressTo(tmp1); | 3516 __ PopReturnAddressTo(tmp1); |
3520 __ Push(left); | 3517 __ Push(left); |
3521 __ Push(right); | 3518 __ Push(right); |
3522 __ PushReturnAddressFrom(tmp1); | 3519 __ PushReturnAddressFrom(tmp1); |
3523 if (equality) { | 3520 if (equality) { |
3524 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); | 3521 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
(...skipping 1109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4634 return_value_operand, | 4631 return_value_operand, |
4635 NULL); | 4632 NULL); |
4636 } | 4633 } |
4637 | 4634 |
4638 | 4635 |
4639 #undef __ | 4636 #undef __ |
4640 | 4637 |
4641 } } // namespace v8::internal | 4638 } } // namespace v8::internal |
4642 | 4639 |
4643 #endif // V8_TARGET_ARCH_X64 | 4640 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |