| 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 4382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4393 __ cmp(r0, ip); | 4393 __ cmp(r0, ip); |
| 4394 __ b(ne, &runtime); | 4394 __ b(ne, &runtime); |
| 4395 // Check that the last match info has space for the capture registers and the | 4395 // Check that the last match info has space for the capture registers and the |
| 4396 // additional information. | 4396 // additional information. |
| 4397 __ ldr(r0, | 4397 __ ldr(r0, |
| 4398 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); | 4398 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); |
| 4399 __ add(r2, r2, Operand(RegExpImpl::kLastMatchOverhead)); | 4399 __ add(r2, r2, Operand(RegExpImpl::kLastMatchOverhead)); |
| 4400 __ cmp(r2, Operand(r0, ASR, kSmiTagSize)); | 4400 __ cmp(r2, Operand(r0, ASR, kSmiTagSize)); |
| 4401 __ b(gt, &runtime); | 4401 __ b(gt, &runtime); |
| 4402 | 4402 |
| 4403 // Reset offset for possibly sliced string. |
| 4404 __ mov(r9, Operand(0)); |
| 4403 // subject: Subject string | 4405 // subject: Subject string |
| 4404 // regexp_data: RegExp data (FixedArray) | 4406 // regexp_data: RegExp data (FixedArray) |
| 4405 // Check the representation and encoding of the subject string. | 4407 // Check the representation and encoding of the subject string. |
| 4406 Label seq_string; | 4408 Label seq_string; |
| 4407 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 4409 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
| 4408 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 4410 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
| 4409 // First check for flat string. | 4411 // First check for flat string. |
| 4410 __ tst(r0, Operand(kIsNotStringMask | kStringRepresentationMask)); | 4412 __ and_(r1, r0, Operand(kIsNotStringMask | kStringRepresentationMask), SetCC); |
| 4411 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); | 4413 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); |
| 4412 __ b(eq, &seq_string); | 4414 __ b(eq, &seq_string); |
| 4413 | 4415 |
| 4414 // subject: Subject string | 4416 // subject: Subject string |
| 4415 // regexp_data: RegExp data (FixedArray) | 4417 // regexp_data: RegExp data (FixedArray) |
| 4416 // Check for flat cons string. | 4418 // Check for flat cons string or sliced string. |
| 4417 // A flat cons string is a cons string where the second part is the empty | 4419 // A flat cons string is a cons string where the second part is the empty |
| 4418 // string. In that case the subject string is just the first part of the cons | 4420 // string. In that case the subject string is just the first part of the cons |
| 4419 // string. Also in this case the first part of the cons string is known to be | 4421 // string. Also in this case the first part of the cons string is known to be |
| 4420 // a sequential string or an external string. | 4422 // a sequential string or an external string. |
| 4421 STATIC_ASSERT(kExternalStringTag !=0); | 4423 // In the case of a sliced string its offset has to be taken into account. |
| 4422 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); | 4424 Label cons_string, check_encoding; |
| 4423 __ tst(r0, Operand(kIsNotStringMask | kExternalStringTag)); | 4425 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| 4424 __ b(ne, &runtime); | 4426 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
| 4427 __ cmp(r1, Operand(kExternalStringTag)); |
| 4428 __ b(lt, &cons_string); |
| 4429 __ b(eq, &runtime); |
| 4430 |
| 4431 // String is sliced. |
| 4432 __ ldr(r9, FieldMemOperand(subject, SlicedString::kOffsetOffset)); |
| 4433 __ mov(r9, Operand(r9, ASR, kSmiTagSize)); |
| 4434 __ ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); |
| 4435 // r9: offset of sliced string, smi-tagged. |
| 4436 __ jmp(&check_encoding); |
| 4437 // String is a cons string, check whether it is flat. |
| 4438 __ bind(&cons_string); |
| 4425 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); | 4439 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); |
| 4426 __ LoadRoot(r1, Heap::kEmptyStringRootIndex); | 4440 __ LoadRoot(r1, Heap::kEmptyStringRootIndex); |
| 4427 __ cmp(r0, r1); | 4441 __ cmp(r0, r1); |
| 4428 __ b(ne, &runtime); | 4442 __ b(ne, &runtime); |
| 4429 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | 4443 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); |
| 4444 // Is first part of cons or parent of slice a flat string? |
| 4445 __ bind(&check_encoding); |
| 4430 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 4446 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
| 4431 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 4447 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
| 4432 // Is first part a flat string? | |
| 4433 STATIC_ASSERT(kSeqStringTag == 0); | 4448 STATIC_ASSERT(kSeqStringTag == 0); |
| 4434 __ tst(r0, Operand(kStringRepresentationMask)); | 4449 __ tst(r0, Operand(kStringRepresentationMask)); |
| 4435 __ b(ne, &runtime); | 4450 __ b(ne, &runtime); |
| 4436 | |
| 4437 __ bind(&seq_string); | 4451 __ bind(&seq_string); |
| 4438 // subject: Subject string | 4452 // subject: Subject string |
| 4439 // regexp_data: RegExp data (FixedArray) | 4453 // regexp_data: RegExp data (FixedArray) |
| 4440 // r0: Instance type of subject string | 4454 // r0: Instance type of subject string |
| 4441 STATIC_ASSERT(4 == kAsciiStringTag); | 4455 STATIC_ASSERT(4 == kAsciiStringTag); |
| 4442 STATIC_ASSERT(kTwoByteStringTag == 0); | 4456 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 4443 // Find the code object based on the assumptions above. | 4457 // Find the code object based on the assumptions above. |
| 4444 __ and_(r0, r0, Operand(kStringEncodingMask)); | 4458 __ and_(r0, r0, Operand(kStringEncodingMask)); |
| 4445 __ mov(r3, Operand(r0, ASR, 2), SetCC); | 4459 __ mov(r3, Operand(r0, ASR, 2), SetCC); |
| 4446 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); | 4460 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4492 __ add(r0, r0, Operand(r2)); | 4506 __ add(r0, r0, Operand(r2)); |
| 4493 __ str(r0, MemOperand(sp, 2 * kPointerSize)); | 4507 __ str(r0, MemOperand(sp, 2 * kPointerSize)); |
| 4494 | 4508 |
| 4495 // Argument 5 (sp[4]): static offsets vector buffer. | 4509 // Argument 5 (sp[4]): static offsets vector buffer. |
| 4496 __ mov(r0, | 4510 __ mov(r0, |
| 4497 Operand(ExternalReference::address_of_static_offsets_vector(isolate))); | 4511 Operand(ExternalReference::address_of_static_offsets_vector(isolate))); |
| 4498 __ str(r0, MemOperand(sp, 1 * kPointerSize)); | 4512 __ str(r0, MemOperand(sp, 1 * kPointerSize)); |
| 4499 | 4513 |
| 4500 // For arguments 4 and 3 get string length, calculate start of string data and | 4514 // For arguments 4 and 3 get string length, calculate start of string data and |
| 4501 // calculate the shift of the index (0 for ASCII and 1 for two byte). | 4515 // calculate the shift of the index (0 for ASCII and 1 for two byte). |
| 4502 __ ldr(r0, FieldMemOperand(subject, String::kLengthOffset)); | |
| 4503 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); | |
| 4504 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); | 4516 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
| 4505 __ add(r9, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 4517 __ add(r8, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 4506 __ eor(r3, r3, Operand(1)); | 4518 __ eor(r3, r3, Operand(1)); |
| 4507 // Argument 4 (r3): End of string data | 4519 // Load the length from the original subject string from the previous stack |
| 4508 // Argument 3 (r2): Start of string data | 4520 // frame. Therefore we have to use fp, which points exactly to two pointer |
| 4521 // sizes below the previous sp. (Because creating a new stack frame pushes |
| 4522 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) |
| 4523 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); |
| 4524 // If slice offset is not 0, load the length from the original sliced string. |
| 4525 // Argument 4, r3: End of string data |
| 4526 // Argument 3, r2: Start of string data |
| 4527 // Prepare start and end index of the input. |
| 4528 __ add(r9, r8, Operand(r9, LSL, r3)); |
| 4509 __ add(r2, r9, Operand(r1, LSL, r3)); | 4529 __ add(r2, r9, Operand(r1, LSL, r3)); |
| 4510 __ add(r3, r9, Operand(r0, LSL, r3)); | 4530 |
| 4531 __ ldr(r8, FieldMemOperand(subject, String::kLengthOffset)); |
| 4532 __ mov(r8, Operand(r8, ASR, kSmiTagSize)); |
| 4533 __ add(r3, r9, Operand(r8, LSL, r3)); |
| 4511 | 4534 |
| 4512 // Argument 2 (r1): Previous index. | 4535 // Argument 2 (r1): Previous index. |
| 4513 // Already there | 4536 // Already there |
| 4514 | 4537 |
| 4515 // Argument 1 (r0): Subject string. | 4538 // Argument 1 (r0): Subject string. |
| 4516 __ mov(r0, subject); | 4539 __ mov(r0, subject); |
| 4517 | 4540 |
| 4518 // Locate the code entry and call it. | 4541 // Locate the code entry and call it. |
| 4519 __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); | 4542 __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 4520 DirectCEntryStub stub; | 4543 DirectCEntryStub stub; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4546 __ ldr(r1, MemOperand(r1, 0)); | 4569 __ ldr(r1, MemOperand(r1, 0)); |
| 4547 __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address, | 4570 __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address, |
| 4548 isolate))); | 4571 isolate))); |
| 4549 __ ldr(r0, MemOperand(r2, 0)); | 4572 __ ldr(r0, MemOperand(r2, 0)); |
| 4550 __ cmp(r0, r1); | 4573 __ cmp(r0, r1); |
| 4551 __ b(eq, &runtime); | 4574 __ b(eq, &runtime); |
| 4552 | 4575 |
| 4553 __ str(r1, MemOperand(r2, 0)); // Clear pending exception. | 4576 __ str(r1, MemOperand(r2, 0)); // Clear pending exception. |
| 4554 | 4577 |
| 4555 // Check if the exception is a termination. If so, throw as uncatchable. | 4578 // Check if the exception is a termination. If so, throw as uncatchable. |
| 4556 __ LoadRoot(ip, Heap::kTerminationExceptionRootIndex); | 4579 __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex); |
| 4557 __ cmp(r0, ip); | 4580 |
| 4558 Label termination_exception; | 4581 Label termination_exception; |
| 4559 __ b(eq, &termination_exception); | 4582 __ b(eq, &termination_exception); |
| 4560 | 4583 |
| 4561 __ Throw(r0); // Expects thrown value in r0. | 4584 __ Throw(r0); // Expects thrown value in r0. |
| 4562 | 4585 |
| 4563 __ bind(&termination_exception); | 4586 __ bind(&termination_exception); |
| 4564 __ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0. | 4587 __ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0. |
| 4565 | 4588 |
| 4566 __ bind(&failure); | 4589 __ bind(&failure); |
| 4567 // For failure and exception return null. | 4590 // For failure and exception return null. |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4838 | IncludeNumberCompareField::encode(include_number_compare_) | 4861 | IncludeNumberCompareField::encode(include_number_compare_) |
| 4839 | IncludeSmiCompareField::encode(include_smi_compare_); | 4862 | IncludeSmiCompareField::encode(include_smi_compare_); |
| 4840 } | 4863 } |
| 4841 | 4864 |
| 4842 | 4865 |
| 4843 // StringCharCodeAtGenerator | 4866 // StringCharCodeAtGenerator |
| 4844 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 4867 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 4845 Label flat_string; | 4868 Label flat_string; |
| 4846 Label ascii_string; | 4869 Label ascii_string; |
| 4847 Label got_char_code; | 4870 Label got_char_code; |
| 4871 Label sliced_string; |
| 4848 | 4872 |
| 4849 // If the receiver is a smi trigger the non-string case. | 4873 // If the receiver is a smi trigger the non-string case. |
| 4850 __ JumpIfSmi(object_, receiver_not_string_); | 4874 __ JumpIfSmi(object_, receiver_not_string_); |
| 4851 | 4875 |
| 4852 // Fetch the instance type of the receiver into result register. | 4876 // Fetch the instance type of the receiver into result register. |
| 4853 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 4877 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
| 4854 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 4878 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
| 4855 // If the receiver is not a string trigger the non-string case. | 4879 // If the receiver is not a string trigger the non-string case. |
| 4856 __ tst(result_, Operand(kIsNotStringMask)); | 4880 __ tst(result_, Operand(kIsNotStringMask)); |
| 4857 __ b(ne, receiver_not_string_); | 4881 __ b(ne, receiver_not_string_); |
| 4858 | 4882 |
| 4859 // If the index is non-smi trigger the non-smi case. | 4883 // If the index is non-smi trigger the non-smi case. |
| 4860 __ JumpIfNotSmi(index_, &index_not_smi_); | 4884 __ JumpIfNotSmi(index_, &index_not_smi_); |
| 4861 | 4885 |
| 4862 // Put smi-tagged index into scratch register. | 4886 // Put smi-tagged index into scratch register. |
| 4863 __ mov(scratch_, index_); | 4887 __ mov(scratch_, index_); |
| 4864 __ bind(&got_smi_index_); | 4888 __ bind(&got_smi_index_); |
| 4865 | 4889 |
| 4866 // Check for index out of range. | 4890 // Check for index out of range. |
| 4867 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset)); | 4891 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset)); |
| 4868 __ cmp(ip, Operand(scratch_)); | 4892 __ cmp(ip, Operand(scratch_)); |
| 4869 __ b(ls, index_out_of_range_); | 4893 __ b(ls, index_out_of_range_); |
| 4870 | 4894 |
| 4871 // We need special handling for non-flat strings. | 4895 // We need special handling for non-flat strings. |
| 4872 STATIC_ASSERT(kSeqStringTag == 0); | 4896 STATIC_ASSERT(kSeqStringTag == 0); |
| 4873 __ tst(result_, Operand(kStringRepresentationMask)); | 4897 __ tst(result_, Operand(kStringRepresentationMask)); |
| 4874 __ b(eq, &flat_string); | 4898 __ b(eq, &flat_string); |
| 4875 | 4899 |
| 4876 // Handle non-flat strings. | 4900 // Handle non-flat strings. |
| 4877 __ tst(result_, Operand(kIsConsStringMask)); | 4901 __ and_(result_, result_, Operand(kStringRepresentationMask)); |
| 4902 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| 4903 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
| 4904 __ cmp(result_, Operand(kExternalStringTag)); |
| 4905 __ b(gt, &sliced_string); |
| 4878 __ b(eq, &call_runtime_); | 4906 __ b(eq, &call_runtime_); |
| 4879 | 4907 |
| 4880 // ConsString. | 4908 // ConsString. |
| 4881 // Check whether the right hand side is the empty string (i.e. if | 4909 // Check whether the right hand side is the empty string (i.e. if |
| 4882 // this is really a flat string in a cons string). If that is not | 4910 // this is really a flat string in a cons string). If that is not |
| 4883 // the case we would rather go to the runtime system now to flatten | 4911 // the case we would rather go to the runtime system now to flatten |
| 4884 // the string. | 4912 // the string. |
| 4913 Label assure_seq_string; |
| 4885 __ ldr(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); | 4914 __ ldr(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); |
| 4886 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); | 4915 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); |
| 4887 __ cmp(result_, Operand(ip)); | 4916 __ cmp(result_, Operand(ip)); |
| 4888 __ b(ne, &call_runtime_); | 4917 __ b(ne, &call_runtime_); |
| 4889 // Get the first of the two strings and load its instance type. | 4918 // Get the first of the two strings and load its instance type. |
| 4890 __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); | 4919 __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); |
| 4920 __ jmp(&assure_seq_string); |
| 4921 |
| 4922 // SlicedString, unpack and add offset. |
| 4923 __ bind(&sliced_string); |
| 4924 __ ldr(result_, FieldMemOperand(object_, SlicedString::kOffsetOffset)); |
| 4925 __ add(scratch_, scratch_, result_); |
| 4926 __ ldr(object_, FieldMemOperand(object_, SlicedString::kParentOffset)); |
| 4927 |
| 4928 // Assure that we are dealing with a sequential string. Go to runtime if not. |
| 4929 __ bind(&assure_seq_string); |
| 4891 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 4930 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
| 4892 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 4931 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
| 4893 // If the first cons component is also non-flat, then go to runtime. | 4932 // Check that parent is not an external string. Go to runtime otherwise. |
| 4894 STATIC_ASSERT(kSeqStringTag == 0); | 4933 STATIC_ASSERT(kSeqStringTag == 0); |
| 4895 __ tst(result_, Operand(kStringRepresentationMask)); | 4934 __ tst(result_, Operand(kStringRepresentationMask)); |
| 4896 __ b(ne, &call_runtime_); | 4935 __ b(ne, &call_runtime_); |
| 4897 | 4936 |
| 4898 // Check for 1-byte or 2-byte string. | 4937 // Check for 1-byte or 2-byte string. |
| 4899 __ bind(&flat_string); | 4938 __ bind(&flat_string); |
| 4900 STATIC_ASSERT(kAsciiStringTag != 0); | 4939 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| 4940 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 4901 __ tst(result_, Operand(kStringEncodingMask)); | 4941 __ tst(result_, Operand(kStringEncodingMask)); |
| 4902 __ b(ne, &ascii_string); | 4942 __ b(ne, &ascii_string); |
| 4903 | 4943 |
| 4904 // 2-byte string. | 4944 // 2-byte string. |
| 4905 // Load the 2-byte character code into the result register. We can | 4945 // Load the 2-byte character code into the result register. We can |
| 4906 // add without shifting since the smi tag size is the log2 of the | 4946 // add without shifting since the smi tag size is the log2 of the |
| 4907 // number of bytes in a two-byte character. | 4947 // number of bytes in a two-byte character. |
| 4908 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); | 4948 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); |
| 4909 __ add(scratch_, object_, Operand(scratch_)); | 4949 __ add(scratch_, object_, Operand(scratch_)); |
| 4910 __ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); | 4950 __ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); |
| (...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5463 // 0 <= from <= to <= string.length. | 5503 // 0 <= from <= to <= string.length. |
| 5464 // If any of these assumptions fail, we call the runtime system. | 5504 // If any of these assumptions fail, we call the runtime system. |
| 5465 | 5505 |
| 5466 static const int kToOffset = 0 * kPointerSize; | 5506 static const int kToOffset = 0 * kPointerSize; |
| 5467 static const int kFromOffset = 1 * kPointerSize; | 5507 static const int kFromOffset = 1 * kPointerSize; |
| 5468 static const int kStringOffset = 2 * kPointerSize; | 5508 static const int kStringOffset = 2 * kPointerSize; |
| 5469 | 5509 |
| 5470 // Check bounds and smi-ness. | 5510 // Check bounds and smi-ness. |
| 5471 Register to = r6; | 5511 Register to = r6; |
| 5472 Register from = r7; | 5512 Register from = r7; |
| 5513 |
| 5473 __ Ldrd(to, from, MemOperand(sp, kToOffset)); | 5514 __ Ldrd(to, from, MemOperand(sp, kToOffset)); |
| 5474 STATIC_ASSERT(kFromOffset == kToOffset + 4); | 5515 STATIC_ASSERT(kFromOffset == kToOffset + 4); |
| 5475 STATIC_ASSERT(kSmiTag == 0); | 5516 STATIC_ASSERT(kSmiTag == 0); |
| 5476 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 5517 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
| 5518 |
| 5477 // I.e., arithmetic shift right by one un-smi-tags. | 5519 // I.e., arithmetic shift right by one un-smi-tags. |
| 5478 __ mov(r2, Operand(to, ASR, 1), SetCC); | 5520 __ mov(r2, Operand(to, ASR, 1), SetCC); |
| 5479 __ mov(r3, Operand(from, ASR, 1), SetCC, cc); | 5521 __ mov(r3, Operand(from, ASR, 1), SetCC, cc); |
| 5480 // If either to or from had the smi tag bit set, then carry is set now. | 5522 // If either to or from had the smi tag bit set, then carry is set now. |
| 5481 __ b(cs, &runtime); // Either "from" or "to" is not a smi. | 5523 __ b(cs, &runtime); // Either "from" or "to" is not a smi. |
| 5482 __ b(mi, &runtime); // From is negative. | 5524 __ b(mi, &runtime); // From is negative. |
| 5483 | 5525 |
| 5484 // Both to and from are smis. | 5526 // Both to and from are smis. |
| 5485 | |
| 5486 __ sub(r2, r2, Operand(r3), SetCC); | 5527 __ sub(r2, r2, Operand(r3), SetCC); |
| 5487 __ b(mi, &runtime); // Fail if from > to. | 5528 __ b(mi, &runtime); // Fail if from > to. |
| 5488 // Special handling of sub-strings of length 1 and 2. One character strings | 5529 // Special handling of sub-strings of length 1 and 2. One character strings |
| 5489 // are handled in the runtime system (looked up in the single character | 5530 // are handled in the runtime system (looked up in the single character |
| 5490 // cache). Two character strings are looked for in the symbol cache. | 5531 // cache). Two character strings are looked for in the symbol cache in |
| 5532 // generated code. |
| 5491 __ cmp(r2, Operand(2)); | 5533 __ cmp(r2, Operand(2)); |
| 5492 __ b(lt, &runtime); | 5534 __ b(lt, &runtime); |
| 5493 | 5535 |
| 5494 // r2: length | 5536 // r2: result string length |
| 5495 // r3: from index (untaged smi) | 5537 // r3: from index (untagged smi) |
| 5496 // r6 (a.k.a. to): to (smi) | 5538 // r6 (a.k.a. to): to (smi) |
| 5497 // r7 (a.k.a. from): from offset (smi) | 5539 // r7 (a.k.a. from): from offset (smi) |
| 5498 | |
| 5499 // Make sure first argument is a sequential (or flat) string. | 5540 // Make sure first argument is a sequential (or flat) string. |
| 5500 __ ldr(r5, MemOperand(sp, kStringOffset)); | 5541 __ ldr(r0, MemOperand(sp, kStringOffset)); |
| 5501 STATIC_ASSERT(kSmiTag == 0); | 5542 STATIC_ASSERT(kSmiTag == 0); |
| 5502 __ JumpIfSmi(r5, &runtime); | 5543 __ JumpIfSmi(r0, &runtime); |
| 5503 Condition is_string = masm->IsObjectStringType(r5, r1); | 5544 Condition is_string = masm->IsObjectStringType(r0, r1); |
| 5504 __ b(NegateCondition(is_string), &runtime); | 5545 __ b(NegateCondition(is_string), &runtime); |
| 5505 | 5546 |
| 5547 // Short-cut for the case of trivial substring. |
| 5548 Label return_r0; |
| 5549 // r0: original string |
| 5550 // r2: result string length |
| 5551 __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset)); |
| 5552 __ cmp(r2, Operand(r4, ASR, 1)); |
| 5553 __ b(eq, &return_r0); |
| 5554 |
| 5555 Label create_slice; |
| 5556 if (FLAG_string_slices) { |
| 5557 __ cmp(r2, Operand(SlicedString::kMinLength)); |
| 5558 __ b(ge, &create_slice); |
| 5559 } |
| 5560 |
| 5561 // r0: original string |
| 5506 // r1: instance type | 5562 // r1: instance type |
| 5507 // r2: length | 5563 // r2: result string length |
| 5508 // r3: from index (untagged smi) | 5564 // r3: from index (untagged smi) |
| 5509 // r5: string | |
| 5510 // r6 (a.k.a. to): to (smi) | 5565 // r6 (a.k.a. to): to (smi) |
| 5511 // r7 (a.k.a. from): from offset (smi) | 5566 // r7 (a.k.a. from): from offset (smi) |
| 5512 Label seq_string; | 5567 Label seq_string; |
| 5513 __ and_(r4, r1, Operand(kStringRepresentationMask)); | 5568 __ and_(r4, r1, Operand(kStringRepresentationMask)); |
| 5514 STATIC_ASSERT(kSeqStringTag < kConsStringTag); | 5569 STATIC_ASSERT(kSeqStringTag < kConsStringTag); |
| 5515 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | 5570 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| 5571 STATIC_ASSERT(kConsStringTag < kSlicedStringTag); |
| 5516 __ cmp(r4, Operand(kConsStringTag)); | 5572 __ cmp(r4, Operand(kConsStringTag)); |
| 5517 __ b(gt, &runtime); // External strings go to runtime. | 5573 __ b(gt, &runtime); // Slices and external strings go to runtime. |
| 5518 __ b(lt, &seq_string); // Sequential strings are handled directly. | 5574 __ b(lt, &seq_string); // Sequential strings are handled directly. |
| 5519 | 5575 |
| 5520 // Cons string. Try to recurse (once) on the first substring. | 5576 // Cons string. Try to recurse (once) on the first substring. |
| 5521 // (This adds a little more generality than necessary to handle flattened | 5577 // (This adds a little more generality than necessary to handle flattened |
| 5522 // cons strings, but not much). | 5578 // cons strings, but not much). |
| 5523 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); | 5579 __ ldr(r0, FieldMemOperand(r0, ConsString::kFirstOffset)); |
| 5524 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); | 5580 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 5525 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 5581 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 5526 __ tst(r1, Operand(kStringRepresentationMask)); | 5582 __ tst(r1, Operand(kStringRepresentationMask)); |
| 5527 STATIC_ASSERT(kSeqStringTag == 0); | 5583 STATIC_ASSERT(kSeqStringTag == 0); |
| 5528 __ b(ne, &runtime); // Cons and External strings go to runtime. | 5584 __ b(ne, &runtime); // Cons, slices and external strings go to runtime. |
| 5529 | 5585 |
| 5530 // Definitly a sequential string. | 5586 // Definitly a sequential string. |
| 5531 __ bind(&seq_string); | 5587 __ bind(&seq_string); |
| 5532 | 5588 |
| 5533 // r1: instance type. | 5589 // r0: original string |
| 5534 // r2: length | 5590 // r1: instance type |
| 5535 // r3: from index (untaged smi) | 5591 // r2: result string length |
| 5536 // r5: string | 5592 // r3: from index (untagged smi) |
| 5537 // r6 (a.k.a. to): to (smi) | 5593 // r6 (a.k.a. to): to (smi) |
| 5538 // r7 (a.k.a. from): from offset (smi) | 5594 // r7 (a.k.a. from): from offset (smi) |
| 5539 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); | 5595 __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset)); |
| 5540 __ cmp(r4, Operand(to)); | 5596 __ cmp(r4, Operand(to)); |
| 5541 __ b(lt, &runtime); // Fail if to > length. | 5597 __ b(lt, &runtime); // Fail if to > length. |
| 5542 to = no_reg; | 5598 to = no_reg; |
| 5543 | 5599 |
| 5544 // r1: instance type. | 5600 // r0: original string or left hand side of the original cons string. |
| 5545 // r2: result string length. | 5601 // r1: instance type |
| 5546 // r3: from index (untaged smi) | 5602 // r2: result string length |
| 5547 // r5: string. | 5603 // r3: from index (untagged smi) |
| 5548 // r7 (a.k.a. from): from offset (smi) | 5604 // r7 (a.k.a. from): from offset (smi) |
| 5549 // Check for flat ASCII string. | 5605 // Check for flat ASCII string. |
| 5550 Label non_ascii_flat; | 5606 Label non_ascii_flat; |
| 5551 __ tst(r1, Operand(kStringEncodingMask)); | 5607 __ tst(r1, Operand(kStringEncodingMask)); |
| 5552 STATIC_ASSERT(kTwoByteStringTag == 0); | 5608 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 5553 __ b(eq, &non_ascii_flat); | 5609 __ b(eq, &non_ascii_flat); |
| 5554 | 5610 |
| 5555 Label result_longer_than_two; | 5611 Label result_longer_than_two; |
| 5556 __ cmp(r2, Operand(2)); | 5612 __ cmp(r2, Operand(2)); |
| 5557 __ b(gt, &result_longer_than_two); | 5613 __ b(gt, &result_longer_than_two); |
| 5558 | 5614 |
| 5559 // Sub string of length 2 requested. | 5615 // Sub string of length 2 requested. |
| 5560 // Get the two characters forming the sub string. | 5616 // Get the two characters forming the sub string. |
| 5561 __ add(r5, r5, Operand(r3)); | 5617 __ add(r0, r0, Operand(r3)); |
| 5562 __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); | 5618 __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 5563 __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1)); | 5619 __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1)); |
| 5564 | 5620 |
| 5565 // Try to lookup two character string in symbol table. | 5621 // Try to lookup two character string in symbol table. |
| 5566 Label make_two_character_string; | 5622 Label make_two_character_string; |
| 5567 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 5623 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
| 5568 masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); | 5624 masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); |
| 5569 Counters* counters = masm->isolate()->counters(); | 5625 Counters* counters = masm->isolate()->counters(); |
| 5570 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); | 5626 __ jmp(&return_r0); |
| 5571 __ add(sp, sp, Operand(3 * kPointerSize)); | |
| 5572 __ Ret(); | |
| 5573 | 5627 |
| 5574 // r2: result string length. | 5628 // r2: result string length. |
| 5575 // r3: two characters combined into halfword in little endian byte order. | 5629 // r3: two characters combined into halfword in little endian byte order. |
| 5576 __ bind(&make_two_character_string); | 5630 __ bind(&make_two_character_string); |
| 5577 __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); | 5631 __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); |
| 5578 __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); | 5632 __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 5579 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); | 5633 __ jmp(&return_r0); |
| 5580 __ add(sp, sp, Operand(3 * kPointerSize)); | |
| 5581 __ Ret(); | |
| 5582 | 5634 |
| 5583 __ bind(&result_longer_than_two); | 5635 __ bind(&result_longer_than_two); |
| 5584 | 5636 |
| 5637 // Locate 'from' character of string. |
| 5638 __ add(r5, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5639 __ add(r5, r5, Operand(from, ASR, 1)); |
| 5640 |
| 5585 // Allocate the result. | 5641 // Allocate the result. |
| 5586 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); | 5642 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); |
| 5587 | 5643 |
| 5588 // r0: result string. | 5644 // r0: result string |
| 5589 // r2: result string length. | 5645 // r2: result string length |
| 5590 // r5: string. | 5646 // r5: first character of substring to copy |
| 5591 // r7 (a.k.a. from): from offset (smi) | 5647 // r7 (a.k.a. from): from offset (smi) |
| 5592 // Locate first character of result. | 5648 // Locate first character of result. |
| 5593 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 5649 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5594 // Locate 'from' character of string. | |
| 5595 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
| 5596 __ add(r5, r5, Operand(from, ASR, 1)); | |
| 5597 | 5650 |
| 5598 // r0: result string. | 5651 // r0: result string |
| 5599 // r1: first character of result string. | 5652 // r1: first character of result string |
| 5600 // r2: result string length. | 5653 // r2: result string length |
| 5601 // r5: first character of sub string to copy. | 5654 // r5: first character of substring to copy |
| 5602 STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); | 5655 STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 5603 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 5656 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
| 5604 COPY_ASCII | DEST_ALWAYS_ALIGNED); | 5657 COPY_ASCII | DEST_ALWAYS_ALIGNED); |
| 5605 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); | 5658 __ jmp(&return_r0); |
| 5606 __ add(sp, sp, Operand(3 * kPointerSize)); | |
| 5607 __ Ret(); | |
| 5608 | 5659 |
| 5609 __ bind(&non_ascii_flat); | 5660 __ bind(&non_ascii_flat); |
| 5610 // r2: result string length. | 5661 // r0: original string |
| 5611 // r5: string. | 5662 // r2: result string length |
| 5612 // r7 (a.k.a. from): from offset (smi) | 5663 // r7 (a.k.a. from): from offset (smi) |
| 5613 // Check for flat two byte string. | 5664 // Check for flat two byte string. |
| 5614 | 5665 |
| 5666 // Locate 'from' character of string. |
| 5667 __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 5668 // As "from" is a smi it is 2 times the value which matches the size of a two |
| 5669 // byte character. |
| 5670 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| 5671 __ add(r5, r5, Operand(from)); |
| 5672 |
| 5615 // Allocate the result. | 5673 // Allocate the result. |
| 5616 __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); | 5674 __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); |
| 5617 | 5675 |
| 5618 // r0: result string. | 5676 // r0: result string |
| 5619 // r2: result string length. | 5677 // r2: result string length |
| 5620 // r5: string. | 5678 // r5: first character of substring to copy |
| 5621 // Locate first character of result. | 5679 // Locate first character of result. |
| 5622 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 5680 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 5623 // Locate 'from' character of string. | 5681 |
| 5624 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
| 5625 // As "from" is a smi it is 2 times the value which matches the size of a two | |
| 5626 // byte character. | |
| 5627 __ add(r5, r5, Operand(from)); | |
| 5628 from = no_reg; | 5682 from = no_reg; |
| 5629 | 5683 |
| 5630 // r0: result string. | 5684 // r0: result string. |
| 5631 // r1: first character of result. | 5685 // r1: first character of result. |
| 5632 // r2: result length. | 5686 // r2: result length. |
| 5633 // r5: first character of string to copy. | 5687 // r5: first character of substring to copy. |
| 5634 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 5688 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 5635 StringHelper::GenerateCopyCharactersLong( | 5689 StringHelper::GenerateCopyCharactersLong( |
| 5636 masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED); | 5690 masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED); |
| 5691 __ jmp(&return_r0); |
| 5692 |
| 5693 if (FLAG_string_slices) { |
| 5694 __ bind(&create_slice); |
| 5695 // r0: original string |
| 5696 // r1: instance type |
| 5697 // r2: length |
| 5698 // r3: from index (untagged smi) |
| 5699 // r6 (a.k.a. to): to (smi) |
| 5700 // r7 (a.k.a. from): from offset (smi) |
| 5701 Label allocate_slice, sliced_string, seq_string; |
| 5702 STATIC_ASSERT(kSeqStringTag == 0); |
| 5703 __ tst(r1, Operand(kStringRepresentationMask)); |
| 5704 __ b(eq, &seq_string); |
| 5705 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
| 5706 STATIC_ASSERT(kIsIndirectStringMask != 0); |
| 5707 __ tst(r1, Operand(kIsIndirectStringMask)); |
| 5708 // External string. Jump to runtime. |
| 5709 __ b(eq, &runtime); |
| 5710 |
| 5711 __ tst(r1, Operand(kSlicedNotConsMask)); |
| 5712 __ b(ne, &sliced_string); |
| 5713 // Cons string. Check whether it is flat, then fetch first part. |
| 5714 __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset)); |
| 5715 __ LoadRoot(r9, Heap::kEmptyStringRootIndex); |
| 5716 __ cmp(r5, r9); |
| 5717 __ b(ne, &runtime); |
| 5718 __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset)); |
| 5719 __ jmp(&allocate_slice); |
| 5720 |
| 5721 __ bind(&sliced_string); |
| 5722 // Sliced string. Fetch parent and correct start index by offset. |
| 5723 __ ldr(r5, FieldMemOperand(r0, SlicedString::kOffsetOffset)); |
| 5724 __ add(r7, r7, r5); |
| 5725 __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); |
| 5726 __ jmp(&allocate_slice); |
| 5727 |
| 5728 __ bind(&seq_string); |
| 5729 // Sequential string. Just move string to the right register. |
| 5730 __ mov(r5, r0); |
| 5731 |
| 5732 __ bind(&allocate_slice); |
| 5733 // r1: instance type of original string |
| 5734 // r2: length |
| 5735 // r5: underlying subject string |
| 5736 // r7 (a.k.a. from): from offset (smi) |
| 5737 // Allocate new sliced string. At this point we do not reload the instance |
| 5738 // type including the string encoding because we simply rely on the info |
| 5739 // provided by the original string. It does not matter if the original |
| 5740 // string's encoding is wrong because we always have to recheck encoding of |
| 5741 // the newly created string's parent anyways due to externalized strings. |
| 5742 Label two_byte_slice, set_slice_header; |
| 5743 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
| 5744 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 5745 __ tst(r1, Operand(kStringEncodingMask)); |
| 5746 __ b(eq, &two_byte_slice); |
| 5747 __ AllocateAsciiSlicedString(r0, r2, r3, r4, &runtime); |
| 5748 __ jmp(&set_slice_header); |
| 5749 __ bind(&two_byte_slice); |
| 5750 __ AllocateTwoByteSlicedString(r0, r2, r3, r4, &runtime); |
| 5751 __ bind(&set_slice_header); |
| 5752 __ str(r7, FieldMemOperand(r0, SlicedString::kOffsetOffset)); |
| 5753 __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); |
| 5754 } |
| 5755 |
| 5756 __ bind(&return_r0); |
| 5637 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); | 5757 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); |
| 5638 __ add(sp, sp, Operand(3 * kPointerSize)); | 5758 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 5639 __ Ret(); | 5759 __ Ret(); |
| 5640 | 5760 |
| 5641 // Just jump to runtime to create the sub string. | 5761 // Just jump to runtime to create the sub string. |
| 5642 __ bind(&runtime); | 5762 __ bind(&runtime); |
| 5643 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 5763 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 5644 } | 5764 } |
| 5645 | 5765 |
| 5646 | 5766 |
| (...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6785 | 6905 |
| 6786 // Fall through when we need to inform the incremental marker. | 6906 // Fall through when we need to inform the incremental marker. |
| 6787 } | 6907 } |
| 6788 | 6908 |
| 6789 | 6909 |
| 6790 #undef __ | 6910 #undef __ |
| 6791 | 6911 |
| 6792 } } // namespace v8::internal | 6912 } } // namespace v8::internal |
| 6793 | 6913 |
| 6794 #endif // V8_TARGET_ARCH_ARM | 6914 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |