OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 5022 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5033 // rax: string | 5033 // rax: string |
5034 // rbx: instance type | 5034 // rbx: instance type |
5035 // Calculate length of sub string using the smi values. | 5035 // Calculate length of sub string using the smi values. |
5036 Label result_longer_than_two; | 5036 Label result_longer_than_two; |
5037 __ movq(rcx, Operand(rsp, kToOffset)); | 5037 __ movq(rcx, Operand(rsp, kToOffset)); |
5038 __ movq(rdx, Operand(rsp, kFromOffset)); | 5038 __ movq(rdx, Operand(rsp, kFromOffset)); |
5039 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); | 5039 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); |
5040 | 5040 |
5041 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. | 5041 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. |
5042 __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx); | 5042 __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx); |
5043 Label return_rax; | 5043 Label not_original_string; |
5044 __ j(equal, &return_rax); | 5044 __ j(not_equal, ¬_original_string, Label::kNear); |
| 5045 Counters* counters = masm->isolate()->counters(); |
| 5046 __ IncrementCounter(counters->sub_string_native(), 1); |
| 5047 __ ret(kArgumentsSize); |
| 5048 __ bind(¬_original_string); |
5045 // Special handling of sub-strings of length 1 and 2. One character strings | 5049 // Special handling of sub-strings of length 1 and 2. One character strings |
5046 // are handled in the runtime system (looked up in the single character | 5050 // are handled in the runtime system (looked up in the single character |
5047 // cache). Two character strings are looked for in the symbol cache. | 5051 // cache). Two character strings are looked for in the symbol cache. |
5048 __ SmiToInteger32(rcx, rcx); | 5052 __ SmiToInteger32(rcx, rcx); |
5049 __ cmpl(rcx, Immediate(2)); | 5053 __ cmpl(rcx, Immediate(2)); |
5050 __ j(greater, &result_longer_than_two); | 5054 __ j(greater, &result_longer_than_two); |
5051 __ j(less, &runtime); | 5055 __ j(less, &runtime); |
5052 | 5056 |
5053 // Sub string of length 2 requested. | 5057 // Sub string of length 2 requested. |
5054 // rax: string | 5058 // rax: string |
5055 // rbx: instance type | 5059 // rbx: instance type |
5056 // rcx: sub string length (value is 2) | 5060 // rcx: sub string length (value is 2) |
5057 // rdx: from index (smi) | 5061 // rdx: from index (smi) |
5058 __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime); | 5062 __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime); |
5059 | 5063 |
5060 // Get the two characters forming the sub string. | 5064 // Get the two characters forming the sub string. |
5061 __ SmiToInteger32(rdx, rdx); // From index is no longer smi. | 5065 __ SmiToInteger32(rdx, rdx); // From index is no longer smi. |
5062 __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize)); | 5066 __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize)); |
5063 __ movzxbq(rcx, | 5067 __ movzxbq(rdi, |
5064 FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1)); | 5068 FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1)); |
5065 | 5069 |
5066 // Try to lookup two character string in symbol table. | 5070 // Try to lookup two character string in symbol table. |
5067 Label make_two_character_string; | 5071 Label make_two_character_string; |
5068 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 5072 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
5069 masm, rbx, rcx, rax, rdx, rdi, r14, &make_two_character_string); | 5073 masm, rbx, rdi, r9, r11, r14, r15, &make_two_character_string); |
| 5074 __ IncrementCounter(counters->sub_string_native(), 1); |
5070 __ ret(3 * kPointerSize); | 5075 __ ret(3 * kPointerSize); |
5071 | 5076 |
5072 __ bind(&make_two_character_string); | 5077 __ bind(&make_two_character_string); |
5073 // Setup registers for allocating the two character string. | 5078 // Setup registers for allocating the two character string. |
5074 __ movq(rax, Operand(rsp, kStringOffset)); | 5079 __ movzxwq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize)); |
5075 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 5080 __ AllocateAsciiString(rax, rcx, r11, r14, r15, &runtime); |
| 5081 __ movw(FieldOperand(rax, SeqAsciiString::kHeaderSize), rbx); |
| 5082 __ IncrementCounter(counters->sub_string_native(), 1); |
| 5083 __ ret(3 * kPointerSize); |
| 5084 |
| 5085 __ bind(&result_longer_than_two); |
| 5086 // rax: string |
| 5087 // rbx: instance type |
| 5088 // rcx: sub string length |
| 5089 // rdx: from index (smi) |
| 5090 // Deal with different string types: update the index if necessary |
| 5091 // and put the underlying string into edi. |
| 5092 Label underlying_unpacked, sliced_string, seq_or_external_string; |
| 5093 // If the string is not indirect, it can only be sequential or external. |
| 5094 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
| 5095 STATIC_ASSERT(kIsIndirectStringMask != 0); |
| 5096 __ testb(rbx, Immediate(kIsIndirectStringMask)); |
| 5097 __ j(zero, &seq_or_external_string, Label::kNear); |
| 5098 |
| 5099 __ testb(rbx, Immediate(kSlicedNotConsMask)); |
| 5100 __ j(not_zero, &sliced_string, Label::kNear); |
| 5101 // Cons string. Check whether it is flat, then fetch first part. |
| 5102 // Flat cons strings have an empty second part. |
| 5103 __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), |
| 5104 Heap::kEmptyStringRootIndex); |
| 5105 __ j(not_equal, &runtime); |
| 5106 __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset)); |
| 5107 // Update instance type. |
| 5108 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
5076 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 5109 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
5077 __ Set(rcx, 2); | 5110 __ jmp(&underlying_unpacked, Label::kNear); |
| 5111 |
| 5112 __ bind(&sliced_string); |
| 5113 // Sliced string. Fetch parent and correct start index by offset. |
| 5114 __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); |
| 5115 __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset)); |
| 5116 // Update instance type. |
| 5117 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 5118 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 5119 __ jmp(&underlying_unpacked, Label::kNear); |
| 5120 |
| 5121 __ bind(&seq_or_external_string); |
| 5122 // Sequential or external string. Just move string to the correct register. |
| 5123 __ movq(rdi, rax); |
| 5124 |
| 5125 __ bind(&underlying_unpacked); |
5078 | 5126 |
5079 if (FLAG_string_slices) { | 5127 if (FLAG_string_slices) { |
5080 Label copy_routine; | 5128 Label copy_routine; |
| 5129 // rdi: underlying subject string |
| 5130 // rbx: instance type of underlying subject string |
| 5131 // rdx: adjusted start index (smi) |
| 5132 // rcx: length |
5081 // If coming from the make_two_character_string path, the string | 5133 // If coming from the make_two_character_string path, the string |
5082 // is too short to be sliced anyways. | 5134 // is too short to be sliced anyways. |
5083 STATIC_ASSERT(2 < SlicedString::kMinLength); | |
5084 __ jmp(©_routine); | |
5085 __ bind(&result_longer_than_two); | |
5086 | |
5087 // rax: string | |
5088 // rbx: instance type | |
5089 // rcx: sub string length | |
5090 // rdx: from index (smi) | |
5091 Label allocate_slice, sliced_string, seq_or_external_string; | |
5092 __ cmpq(rcx, Immediate(SlicedString::kMinLength)); | 5135 __ cmpq(rcx, Immediate(SlicedString::kMinLength)); |
5093 // Short slice. Copy instead of slicing. | 5136 // Short slice. Copy instead of slicing. |
5094 __ j(less, ©_routine); | 5137 __ j(less, ©_routine); |
5095 // If the string is not indirect, it can only be sequential or external. | |
5096 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | |
5097 STATIC_ASSERT(kIsIndirectStringMask != 0); | |
5098 __ testb(rbx, Immediate(kIsIndirectStringMask)); | |
5099 __ j(zero, &seq_or_external_string, Label::kNear); | |
5100 | |
5101 __ testb(rbx, Immediate(kSlicedNotConsMask)); | |
5102 __ j(not_zero, &sliced_string, Label::kNear); | |
5103 // Cons string. Check whether it is flat, then fetch first part. | |
5104 __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), | |
5105 Heap::kEmptyStringRootIndex); | |
5106 __ j(not_equal, &runtime); | |
5107 __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset)); | |
5108 __ jmp(&allocate_slice, Label::kNear); | |
5109 | |
5110 __ bind(&sliced_string); | |
5111 // Sliced string. Fetch parent and correct start index by offset. | |
5112 __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); | |
5113 __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset)); | |
5114 __ jmp(&allocate_slice, Label::kNear); | |
5115 | |
5116 __ bind(&seq_or_external_string); | |
5117 // Sequential or external string. Just move string to the correct register. | |
5118 __ movq(rdi, rax); | |
5119 | |
5120 __ bind(&allocate_slice); | |
5121 // edi: underlying subject string | |
5122 // ebx: instance type of original subject string | |
5123 // edx: offset | |
5124 // ecx: length | |
5125 // Allocate new sliced string. At this point we do not reload the instance | 5138 // Allocate new sliced string. At this point we do not reload the instance |
5126 // type including the string encoding because we simply rely on the info | 5139 // type including the string encoding because we simply rely on the info |
5127 // provided by the original string. It does not matter if the original | 5140 // provided by the original string. It does not matter if the original |
5128 // string's encoding is wrong because we always have to recheck encoding of | 5141 // string's encoding is wrong because we always have to recheck encoding of |
5129 // the newly created string's parent anyways due to externalized strings. | 5142 // the newly created string's parent anyways due to externalized strings. |
5130 Label two_byte_slice, set_slice_header; | 5143 Label two_byte_slice, set_slice_header; |
5131 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | 5144 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
5132 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 5145 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
5133 __ testb(rbx, Immediate(kStringEncodingMask)); | 5146 __ testb(rbx, Immediate(kStringEncodingMask)); |
5134 __ j(zero, &two_byte_slice, Label::kNear); | 5147 __ j(zero, &two_byte_slice, Label::kNear); |
5135 __ AllocateAsciiSlicedString(rax, rbx, no_reg, &runtime); | 5148 __ AllocateAsciiSlicedString(rax, rbx, r14, &runtime); |
5136 __ jmp(&set_slice_header, Label::kNear); | 5149 __ jmp(&set_slice_header, Label::kNear); |
5137 __ bind(&two_byte_slice); | 5150 __ bind(&two_byte_slice); |
5138 __ AllocateTwoByteSlicedString(rax, rbx, no_reg, &runtime); | 5151 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); |
5139 __ bind(&set_slice_header); | 5152 __ bind(&set_slice_header); |
5140 __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); | 5153 __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); |
5141 __ Integer32ToSmi(rcx, rcx); | 5154 __ Integer32ToSmi(rcx, rcx); |
5142 __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); | 5155 __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); |
5143 __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); | 5156 __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); |
5144 __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), | 5157 __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), |
5145 Immediate(String::kEmptyHashField)); | 5158 Immediate(String::kEmptyHashField)); |
5146 __ jmp(&return_rax); | 5159 __ IncrementCounter(counters->sub_string_native(), 1); |
| 5160 __ ret(kArgumentsSize); |
5147 | 5161 |
5148 __ bind(©_routine); | 5162 __ bind(©_routine); |
5149 } else { | |
5150 __ bind(&result_longer_than_two); | |
5151 } | 5163 } |
5152 | 5164 |
5153 // rax: string | 5165 // rdi: underlying subject string |
5154 // rbx: instance type | 5166 // rbx: instance type of underlying subject string |
5155 // rcx: result string length | 5167 // rdx: adjusted start index (smi) |
5156 // Check for flat ascii string | 5168 // rcx: length |
5157 Label non_ascii_flat; | 5169 // The subject string can only be external or sequential string of either |
5158 __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat); | 5170 // encoding at this point. |
| 5171 Label two_byte_sequential, sequential_string; |
| 5172 STATIC_ASSERT(kExternalStringTag != 0); |
| 5173 STATIC_ASSERT(kSeqStringTag == 0); |
| 5174 __ testb(rbx, Immediate(kExternalStringTag)); |
| 5175 __ j(zero, &sequential_string); |
| 5176 |
| 5177 // Handle external string. |
| 5178 // Rule out short external strings. |
| 5179 STATIC_CHECK(kShortExternalStringTag != 0); |
| 5180 __ testb(rbx, Immediate(kShortExternalStringMask)); |
| 5181 __ j(not_zero, &runtime); |
| 5182 __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); |
| 5183 // Move the pointer so that offset-wise, it looks like a sequential string. |
| 5184 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); |
| 5185 __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 5186 |
| 5187 __ bind(&sequential_string); |
| 5188 STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); |
| 5189 __ testb(rbx, Immediate(kStringEncodingMask)); |
| 5190 __ j(zero, &two_byte_sequential); |
5159 | 5191 |
5160 // Allocate the result. | 5192 // Allocate the result. |
5161 __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime); | 5193 __ AllocateAsciiString(rax, rcx, r11, r14, r15, &runtime); |
5162 | 5194 |
5163 // rax: result string | 5195 // rax: result string |
5164 // rcx: result string length | 5196 // rcx: result string length |
5165 __ movq(rdx, rsi); // esi used by following code. | 5197 __ movq(r14, rsi); // esi used by following code. |
| 5198 { // Locate character of sub string start. |
| 5199 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); |
| 5200 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, |
| 5201 SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5202 } |
5166 // Locate first character of result. | 5203 // Locate first character of result. |
5167 __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); | 5204 __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
5168 // Load string argument and locate character of sub string start. | |
5169 __ movq(rsi, Operand(rsp, kStringOffset)); | |
5170 __ movq(rbx, Operand(rsp, kFromOffset)); | |
5171 { | |
5172 SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_1); | |
5173 __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale, | |
5174 SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
5175 } | |
5176 | 5205 |
5177 // rax: result string | 5206 // rax: result string |
5178 // rcx: result length | 5207 // rcx: result length |
5179 // rdx: original value of rsi | |
5180 // rdi: first character of result | 5208 // rdi: first character of result |
5181 // rsi: character of sub string start | 5209 // rsi: character of sub string start |
| 5210 // r14: original value of rsi |
5182 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); | 5211 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); |
5183 __ movq(rsi, rdx); // Restore rsi. | 5212 __ movq(rsi, r14); // Restore rsi. |
5184 Counters* counters = masm->isolate()->counters(); | |
5185 __ IncrementCounter(counters->sub_string_native(), 1); | 5213 __ IncrementCounter(counters->sub_string_native(), 1); |
5186 __ ret(kArgumentsSize); | 5214 __ ret(kArgumentsSize); |
5187 | 5215 |
5188 __ bind(&non_ascii_flat); | 5216 __ bind(&two_byte_sequential); |
5189 // rax: string | |
5190 // rbx: instance type & kStringRepresentationMask | kStringEncodingMask | |
5191 // rcx: result string length | |
5192 // Check for sequential two byte string | |
5193 __ cmpb(rbx, Immediate(kSeqStringTag | kTwoByteStringTag)); | |
5194 __ j(not_equal, &runtime); | |
5195 | |
5196 // Allocate the result. | 5217 // Allocate the result. |
5197 __ AllocateTwoByteString(rax, rcx, rbx, rdx, rdi, &runtime); | 5218 __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime); |
5198 | 5219 |
5199 // rax: result string | 5220 // rax: result string |
5200 // rcx: result string length | 5221 // rcx: result string length |
5201 __ movq(rdx, rsi); // esi used by following code. | 5222 __ movq(r14, rsi); // esi used by following code. |
| 5223 { // Locate character of sub string start. |
| 5224 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); |
| 5225 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, |
| 5226 SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5227 } |
5202 // Locate first character of result. | 5228 // Locate first character of result. |
5203 __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); | 5229 __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); |
5204 // Load string argument and locate character of sub string start. | |
5205 __ movq(rsi, Operand(rsp, kStringOffset)); | |
5206 __ movq(rbx, Operand(rsp, kFromOffset)); | |
5207 { | |
5208 SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_2); | |
5209 __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale, | |
5210 SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
5211 } | |
5212 | 5230 |
5213 // rax: result string | 5231 // rax: result string |
5214 // rcx: result length | 5232 // rcx: result length |
5215 // rdx: original value of rsi | |
5216 // rdi: first character of result | 5233 // rdi: first character of result |
5217 // rsi: character of sub string start | 5234 // rsi: character of sub string start |
| 5235 // r14: original value of rsi |
5218 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); | 5236 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); |
5219 __ movq(rsi, rdx); // Restore esi. | 5237 __ movq(rsi, r14); // Restore esi. |
5220 | |
5221 __ bind(&return_rax); | |
5222 __ IncrementCounter(counters->sub_string_native(), 1); | 5238 __ IncrementCounter(counters->sub_string_native(), 1); |
5223 __ ret(kArgumentsSize); | 5239 __ ret(kArgumentsSize); |
5224 | 5240 |
5225 // Just jump to runtime to create the sub string. | 5241 // Just jump to runtime to create the sub string. |
5226 __ bind(&runtime); | 5242 __ bind(&runtime); |
5227 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 5243 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
5228 } | 5244 } |
5229 | 5245 |
5230 | 5246 |
5231 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, | 5247 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, |
(...skipping 981 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6213 xmm0, | 6229 xmm0, |
6214 &slow_elements); | 6230 &slow_elements); |
6215 __ ret(0); | 6231 __ ret(0); |
6216 } | 6232 } |
6217 | 6233 |
6218 #undef __ | 6234 #undef __ |
6219 | 6235 |
6220 } } // namespace v8::internal | 6236 } } // namespace v8::internal |
6221 | 6237 |
6222 #endif // V8_TARGET_ARCH_X64 | 6238 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |