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 5225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5236 } | 5236 } |
5237 | 5237 |
5238 | 5238 |
5239 // StringCharCodeAtGenerator. | 5239 // StringCharCodeAtGenerator. |
5240 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 5240 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
5241 Label flat_string; | 5241 Label flat_string; |
5242 Label ascii_string; | 5242 Label ascii_string; |
5243 Label got_char_code; | 5243 Label got_char_code; |
5244 Label sliced_string; | 5244 Label sliced_string; |
5245 | 5245 |
5246 ASSERT(!t0.is(scratch_)); | |
5247 ASSERT(!t0.is(index_)); | 5246 ASSERT(!t0.is(index_)); |
5248 ASSERT(!t0.is(result_)); | 5247 ASSERT(!t0.is(result_)); |
5249 ASSERT(!t0.is(object_)); | 5248 ASSERT(!t0.is(object_)); |
5250 | 5249 |
5251 // If the receiver is a smi trigger the non-string case. | 5250 // If the receiver is a smi trigger the non-string case. |
5252 __ JumpIfSmi(object_, receiver_not_string_); | 5251 __ JumpIfSmi(object_, receiver_not_string_); |
5253 | 5252 |
5254 // Fetch the instance type of the receiver into result register. | 5253 // Fetch the instance type of the receiver into result register. |
5255 __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 5254 __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
5256 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 5255 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
5257 // If the receiver is not a string trigger the non-string case. | 5256 // If the receiver is not a string trigger the non-string case. |
5258 __ And(t0, result_, Operand(kIsNotStringMask)); | 5257 __ And(t0, result_, Operand(kIsNotStringMask)); |
5259 __ Branch(receiver_not_string_, ne, t0, Operand(zero_reg)); | 5258 __ Branch(receiver_not_string_, ne, t0, Operand(zero_reg)); |
5260 | 5259 |
5261 // If the index is non-smi trigger the non-smi case. | 5260 // If the index is non-smi trigger the non-smi case. |
5262 __ JumpIfNotSmi(index_, &index_not_smi_); | 5261 __ JumpIfNotSmi(index_, &index_not_smi_); |
5263 | 5262 |
5264 // Put smi-tagged index into scratch register. | |
5265 __ mov(scratch_, index_); | |
5266 __ bind(&got_smi_index_); | 5263 __ bind(&got_smi_index_); |
5267 | 5264 |
5268 // Check for index out of range. | 5265 // Check for index out of range. |
5269 __ lw(t0, FieldMemOperand(object_, String::kLengthOffset)); | 5266 __ lw(t0, FieldMemOperand(object_, String::kLengthOffset)); |
5270 __ Branch(index_out_of_range_, ls, t0, Operand(scratch_)); | 5267 __ Branch(index_out_of_range_, ls, t0, Operand(index_)); |
5271 | 5268 |
5272 // We need special handling for non-flat strings. | 5269 // We need special handling for non-flat strings. |
5273 STATIC_ASSERT(kSeqStringTag == 0); | 5270 STATIC_ASSERT(kSeqStringTag == 0); |
5274 __ And(t0, result_, Operand(kStringRepresentationMask)); | 5271 __ And(t0, result_, Operand(kStringRepresentationMask)); |
5275 __ Branch(&flat_string, eq, t0, Operand(zero_reg)); | 5272 __ Branch(&flat_string, eq, t0, Operand(zero_reg)); |
5276 | 5273 |
5277 // Handle non-flat strings. | 5274 // Handle non-flat strings. |
5278 __ And(result_, result_, Operand(kStringRepresentationMask)); | 5275 __ And(result_, result_, Operand(kStringRepresentationMask)); |
5279 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | 5276 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
5280 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | 5277 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
5281 __ Branch(&sliced_string, gt, result_, Operand(kExternalStringTag)); | 5278 __ Branch(&sliced_string, gt, result_, Operand(kExternalStringTag)); |
5282 __ Branch(&call_runtime_, eq, result_, Operand(kExternalStringTag)); | 5279 __ Branch(&call_runtime_, eq, result_, Operand(kExternalStringTag)); |
5283 | 5280 |
5284 // ConsString. | 5281 // ConsString. |
5285 // Check whether the right hand side is the empty string (i.e. if | 5282 // Check whether the right hand side is the empty string (i.e. if |
5286 // this is really a flat string in a cons string). If that is not | 5283 // this is really a flat string in a cons string). If that is not |
5287 // the case we would rather go to the runtime system now to flatten | 5284 // the case we would rather go to the runtime system now to flatten |
5288 // the string. | 5285 // the string. |
5289 Label assure_seq_string; | 5286 Label assure_seq_string; |
5290 __ lw(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); | 5287 __ lw(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); |
5291 __ LoadRoot(t0, Heap::kEmptyStringRootIndex); | 5288 __ LoadRoot(t0, Heap::kEmptyStringRootIndex); |
5292 __ Branch(&call_runtime_, ne, result_, Operand(t0)); | 5289 __ Branch(&call_runtime_, ne, result_, Operand(t0)); |
5293 | 5290 |
5294 // Get the first of the two strings and load its instance type. | 5291 // Get the first of the two parts. |
5295 __ lw(result_, FieldMemOperand(object_, ConsString::kFirstOffset)); | 5292 __ lw(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); |
5296 __ jmp(&assure_seq_string); | 5293 __ jmp(&assure_seq_string); |
5297 | 5294 |
5298 // SlicedString, unpack and add offset. | 5295 // SlicedString, unpack and add offset. |
5299 __ bind(&sliced_string); | 5296 __ bind(&sliced_string); |
5300 __ lw(result_, FieldMemOperand(object_, SlicedString::kOffsetOffset)); | 5297 __ lw(result_, FieldMemOperand(object_, SlicedString::kOffsetOffset)); |
5301 __ addu(scratch_, scratch_, result_); | 5298 __ Addu(index_, index_, result_); |
5302 __ lw(result_, FieldMemOperand(object_, SlicedString::kParentOffset)); | 5299 __ lw(object_, FieldMemOperand(object_, SlicedString::kParentOffset)); |
5303 | 5300 |
5304 // Assure that we are dealing with a sequential string. Go to runtime if not. | 5301 // Assure that we are dealing with a sequential string. Go to runtime if not. |
5305 __ bind(&assure_seq_string); | 5302 __ bind(&assure_seq_string); |
5306 __ lw(result_, FieldMemOperand(result_, HeapObject::kMapOffset)); | 5303 __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
5307 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 5304 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
5308 // Check that parent is not an external string. Go to runtime otherwise. | 5305 // Check that parent is not an external string. Go to runtime otherwise. |
| 5306 // Note that if the original string is a cons or slice with an external |
| 5307 // string as underlying string, we pass that unpacked underlying string with |
| 5308 // the updated index to the runtime function. |
5309 STATIC_ASSERT(kSeqStringTag == 0); | 5309 STATIC_ASSERT(kSeqStringTag == 0); |
5310 | 5310 |
5311 __ And(t0, result_, Operand(kStringRepresentationMask)); | 5311 __ And(t0, result_, Operand(kStringRepresentationMask)); |
5312 __ Branch(&call_runtime_, ne, t0, Operand(zero_reg)); | 5312 __ Branch(&call_runtime_, ne, t0, Operand(zero_reg)); |
5313 // Actually fetch the parent string if it is confirmed to be sequential. | |
5314 STATIC_ASSERT(SlicedString::kParentOffset == ConsString::kFirstOffset); | |
5315 __ lw(object_, FieldMemOperand(object_, SlicedString::kParentOffset)); | |
5316 | 5313 |
5317 // Check for 1-byte or 2-byte string. | 5314 // Check for 1-byte or 2-byte string. |
5318 __ bind(&flat_string); | 5315 __ bind(&flat_string); |
5319 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | 5316 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
5320 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 5317 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
5321 __ And(t0, result_, Operand(kStringEncodingMask)); | 5318 __ And(t0, result_, Operand(kStringEncodingMask)); |
5322 __ Branch(&ascii_string, ne, t0, Operand(zero_reg)); | 5319 __ Branch(&ascii_string, ne, t0, Operand(zero_reg)); |
5323 | 5320 |
5324 // 2-byte string. | 5321 // 2-byte string. |
5325 // Load the 2-byte character code into the result register. We can | 5322 // Load the 2-byte character code into the result register. We can |
5326 // add without shifting since the smi tag size is the log2 of the | 5323 // add without shifting since the smi tag size is the log2 of the |
5327 // number of bytes in a two-byte character. | 5324 // number of bytes in a two-byte character. |
5328 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); | 5325 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); |
5329 __ Addu(scratch_, object_, Operand(scratch_)); | 5326 __ Addu(index_, object_, Operand(index_)); |
5330 __ lhu(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); | 5327 __ lhu(result_, FieldMemOperand(index_, SeqTwoByteString::kHeaderSize)); |
5331 __ Branch(&got_char_code); | 5328 __ Branch(&got_char_code); |
5332 | 5329 |
5333 // ASCII string. | 5330 // ASCII string. |
5334 // Load the byte into the result register. | 5331 // Load the byte into the result register. |
5335 __ bind(&ascii_string); | 5332 __ bind(&ascii_string); |
5336 | 5333 |
5337 __ srl(t0, scratch_, kSmiTagSize); | 5334 __ srl(t0, index_, kSmiTagSize); |
5338 __ Addu(scratch_, object_, t0); | 5335 __ Addu(index_, object_, t0); |
5339 | 5336 |
5340 __ lbu(result_, FieldMemOperand(scratch_, SeqAsciiString::kHeaderSize)); | 5337 __ lbu(result_, FieldMemOperand(index_, SeqAsciiString::kHeaderSize)); |
5341 | 5338 |
5342 __ bind(&got_char_code); | 5339 __ bind(&got_char_code); |
5343 __ sll(result_, result_, kSmiTagSize); | 5340 __ sll(result_, result_, kSmiTagSize); |
5344 __ bind(&exit_); | 5341 __ bind(&exit_); |
5345 } | 5342 } |
5346 | 5343 |
5347 | 5344 |
5348 void StringCharCodeAtGenerator::GenerateSlow( | 5345 void StringCharCodeAtGenerator::GenerateSlow( |
5349 MacroAssembler* masm, | 5346 MacroAssembler* masm, |
5350 const RuntimeCallHelper& call_helper) { | 5347 const RuntimeCallHelper& call_helper) { |
5351 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); | 5348 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); |
5352 | 5349 |
5353 // Index is not a smi. | 5350 // Index is not a smi. |
5354 __ bind(&index_not_smi_); | 5351 __ bind(&index_not_smi_); |
5355 // If index is a heap number, try converting it to an integer. | 5352 // If index is a heap number, try converting it to an integer. |
5356 __ CheckMap(index_, | 5353 __ CheckMap(index_, |
5357 scratch_, | 5354 result_, |
5358 Heap::kHeapNumberMapRootIndex, | 5355 Heap::kHeapNumberMapRootIndex, |
5359 index_not_number_, | 5356 index_not_number_, |
5360 DONT_DO_SMI_CHECK); | 5357 DONT_DO_SMI_CHECK); |
5361 call_helper.BeforeCall(masm); | 5358 call_helper.BeforeCall(masm); |
5362 // Consumed by runtime conversion function: | 5359 // Consumed by runtime conversion function: |
5363 __ Push(object_, index_, index_); | 5360 __ Push(object_, index_); |
5364 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 5361 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
5365 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); | 5362 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); |
5366 } else { | 5363 } else { |
5367 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 5364 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
5368 // NumberToSmi discards numbers that are not exact integers. | 5365 // NumberToSmi discards numbers that are not exact integers. |
5369 __ CallRuntime(Runtime::kNumberToSmi, 1); | 5366 __ CallRuntime(Runtime::kNumberToSmi, 1); |
5370 } | 5367 } |
5371 | 5368 |
5372 // Save the conversion result before the pop instructions below | 5369 // Save the conversion result before the pop instructions below |
5373 // have a chance to overwrite it. | 5370 // have a chance to overwrite it. |
5374 | 5371 |
5375 __ Move(scratch_, v0); | 5372 __ Move(index_, v0); |
5376 | |
5377 __ pop(index_); | |
5378 __ pop(object_); | 5373 __ pop(object_); |
5379 // Reload the instance type. | 5374 // Reload the instance type. |
5380 __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 5375 __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
5381 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 5376 __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
5382 call_helper.AfterCall(masm); | 5377 call_helper.AfterCall(masm); |
5383 // If index is still not a smi, it must be out of range. | 5378 // If index is still not a smi, it must be out of range. |
5384 __ JumpIfNotSmi(scratch_, index_out_of_range_); | 5379 __ JumpIfNotSmi(index_, index_out_of_range_); |
5385 // Otherwise, return to the fast path. | 5380 // Otherwise, return to the fast path. |
5386 __ Branch(&got_smi_index_); | 5381 __ Branch(&got_smi_index_); |
5387 | 5382 |
5388 // Call runtime. We get here when the receiver is a string and the | 5383 // Call runtime. We get here when the receiver is a string and the |
5389 // index is a number, but the code of getting the actual character | 5384 // index is a number, but the code of getting the actual character |
5390 // is too complex (e.g., when the string needs to be flattened). | 5385 // is too complex (e.g., when the string needs to be flattened). |
5391 __ bind(&call_runtime_); | 5386 __ bind(&call_runtime_); |
5392 call_helper.BeforeCall(masm); | 5387 call_helper.BeforeCall(masm); |
5393 __ Push(object_, index_); | 5388 __ Push(object_, index_); |
5394 __ CallRuntime(Runtime::kStringCharCodeAt, 2); | 5389 __ CallRuntime(Runtime::kStringCharCodeAt, 2); |
(...skipping 2069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7464 | 7459 |
7465 // Fall through when we need to inform the incremental marker. | 7460 // Fall through when we need to inform the incremental marker. |
7466 } | 7461 } |
7467 | 7462 |
7468 | 7463 |
7469 #undef __ | 7464 #undef __ |
7470 | 7465 |
7471 } } // namespace v8::internal | 7466 } } // namespace v8::internal |
7472 | 7467 |
7473 #endif // V8_TARGET_ARCH_MIPS | 7468 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |