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