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 4416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4427 | 4427 |
4428 void StringCharAtGenerator::GenerateSlow( | 4428 void StringCharAtGenerator::GenerateSlow( |
4429 MacroAssembler* masm, | 4429 MacroAssembler* masm, |
4430 const RuntimeCallHelper& call_helper) { | 4430 const RuntimeCallHelper& call_helper) { |
4431 char_code_at_generator_.GenerateSlow(masm, call_helper); | 4431 char_code_at_generator_.GenerateSlow(masm, call_helper); |
4432 char_from_code_generator_.GenerateSlow(masm, call_helper); | 4432 char_from_code_generator_.GenerateSlow(masm, call_helper); |
4433 } | 4433 } |
4434 | 4434 |
4435 | 4435 |
4436 void StringAddStub::Generate(MacroAssembler* masm) { | 4436 void StringAddStub::Generate(MacroAssembler* masm) { |
4437 Label string_add_runtime, call_builtin; | 4437 Label call_runtime, call_builtin; |
4438 Builtins::JavaScript builtin_id = Builtins::ADD; | 4438 Builtins::JavaScript builtin_id = Builtins::ADD; |
4439 | 4439 |
4440 // Load the two arguments. | 4440 // Load the two arguments. |
4441 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). | 4441 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). |
4442 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). | 4442 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). |
4443 | 4443 |
4444 // Make sure that both arguments are strings if not known in advance. | 4444 // Make sure that both arguments are strings if not known in advance. |
4445 if (flags_ == NO_STRING_ADD_FLAGS) { | 4445 if (flags_ == NO_STRING_ADD_FLAGS) { |
4446 __ JumpIfSmi(rax, &string_add_runtime); | 4446 __ JumpIfSmi(rax, &call_runtime); |
4447 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); | 4447 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); |
4448 __ j(above_equal, &string_add_runtime); | 4448 __ j(above_equal, &call_runtime); |
4449 | 4449 |
4450 // First argument is a a string, test second. | 4450 // First argument is a a string, test second. |
4451 __ JumpIfSmi(rdx, &string_add_runtime); | 4451 __ JumpIfSmi(rdx, &call_runtime); |
4452 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | 4452 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
4453 __ j(above_equal, &string_add_runtime); | 4453 __ j(above_equal, &call_runtime); |
4454 } else { | 4454 } else { |
4455 // Here at least one of the arguments is definitely a string. | 4455 // Here at least one of the arguments is definitely a string. |
4456 // We convert the one that is not known to be a string. | 4456 // We convert the one that is not known to be a string. |
4457 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 4457 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { |
4458 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 4458 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); |
4459 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, | 4459 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, |
4460 &call_builtin); | 4460 &call_builtin); |
4461 builtin_id = Builtins::STRING_ADD_RIGHT; | 4461 builtin_id = Builtins::STRING_ADD_RIGHT; |
4462 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 4462 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { |
4463 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 4463 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4511 // Look at the length of the result of adding the two strings. | 4511 // Look at the length of the result of adding the two strings. |
4512 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | 4512 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); |
4513 __ SmiAdd(rbx, rbx, rcx); | 4513 __ SmiAdd(rbx, rbx, rcx); |
4514 // Use the symbol table when adding two one character strings, as it | 4514 // Use the symbol table when adding two one character strings, as it |
4515 // helps later optimizations to return a symbol here. | 4515 // helps later optimizations to return a symbol here. |
4516 __ SmiCompare(rbx, Smi::FromInt(2)); | 4516 __ SmiCompare(rbx, Smi::FromInt(2)); |
4517 __ j(not_equal, &longer_than_two); | 4517 __ j(not_equal, &longer_than_two); |
4518 | 4518 |
4519 // Check that both strings are non-external ascii strings. | 4519 // Check that both strings are non-external ascii strings. |
4520 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, | 4520 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, |
4521 &string_add_runtime); | 4521 &call_runtime); |
4522 | 4522 |
4523 // Get the two characters forming the sub string. | 4523 // Get the two characters forming the sub string. |
4524 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); | 4524 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
4525 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); | 4525 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); |
4526 | 4526 |
4527 // Try to lookup two character string in symbol table. If it is not found | 4527 // Try to lookup two character string in symbol table. If it is not found |
4528 // just allocate a new one. | 4528 // just allocate a new one. |
4529 Label make_two_character_string, make_flat_ascii_string; | 4529 Label make_two_character_string, make_flat_ascii_string; |
4530 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 4530 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
4531 masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string); | 4531 masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string); |
4532 __ IncrementCounter(counters->string_add_native(), 1); | 4532 __ IncrementCounter(counters->string_add_native(), 1); |
4533 __ ret(2 * kPointerSize); | 4533 __ ret(2 * kPointerSize); |
4534 | 4534 |
4535 __ bind(&make_two_character_string); | 4535 __ bind(&make_two_character_string); |
4536 __ Set(rbx, 2); | 4536 __ Set(rdi, 2); |
4537 __ jmp(&make_flat_ascii_string); | 4537 __ AllocateAsciiString(rax, rdi, r8, r9, r11, &call_runtime); |
| 4538 // rbx - first byte: first character |
| 4539 // rbx - second byte: *maybe* second character |
| 4540 // Make sure that the second byte of rbx contains the second character. |
| 4541 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); |
| 4542 __ shll(rcx, Immediate(kBitsPerByte)); |
| 4543 __ orl(rbx, rcx); |
| 4544 // Write both characters to the new string. |
| 4545 __ movw(FieldOperand(rax, SeqAsciiString::kHeaderSize), rbx); |
| 4546 __ IncrementCounter(counters->string_add_native(), 1); |
| 4547 __ ret(2 * kPointerSize); |
4538 | 4548 |
4539 __ bind(&longer_than_two); | 4549 __ bind(&longer_than_two); |
4540 // Check if resulting string will be flat. | 4550 // Check if resulting string will be flat. |
4541 __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength)); | 4551 __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength)); |
4542 __ j(below, &string_add_flat_result); | 4552 __ j(below, &string_add_flat_result); |
4543 // Handle exceptionally long strings in the runtime system. | 4553 // Handle exceptionally long strings in the runtime system. |
4544 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | 4554 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); |
4545 __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength)); | 4555 __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength)); |
4546 __ j(above, &string_add_runtime); | 4556 __ j(above, &call_runtime); |
4547 | 4557 |
4548 // If result is not supposed to be flat, allocate a cons string object. If | 4558 // If result is not supposed to be flat, allocate a cons string object. If |
4549 // both strings are ascii the result is an ascii cons string. | 4559 // both strings are ascii the result is an ascii cons string. |
4550 // rax: first string | 4560 // rax: first string |
4551 // rbx: length of resulting flat string | 4561 // rbx: length of resulting flat string |
4552 // rdx: second string | 4562 // rdx: second string |
4553 // r8: instance type of first string | 4563 // r8: instance type of first string |
4554 // r9: instance type of second string | 4564 // r9: instance type of second string |
4555 Label non_ascii, allocated, ascii_data; | 4565 Label non_ascii, allocated, ascii_data; |
4556 __ movl(rcx, r8); | 4566 __ movl(rcx, r8); |
4557 __ and_(rcx, r9); | 4567 __ and_(rcx, r9); |
4558 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | 4568 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
4559 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 4569 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
4560 __ testl(rcx, Immediate(kStringEncodingMask)); | 4570 __ testl(rcx, Immediate(kStringEncodingMask)); |
4561 __ j(zero, &non_ascii); | 4571 __ j(zero, &non_ascii); |
4562 __ bind(&ascii_data); | 4572 __ bind(&ascii_data); |
4563 // Allocate an acsii cons string. | 4573 // Allocate an acsii cons string. |
4564 __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); | 4574 __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime); |
4565 __ bind(&allocated); | 4575 __ bind(&allocated); |
4566 // Fill the fields of the cons string. | 4576 // Fill the fields of the cons string. |
4567 __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx); | 4577 __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx); |
4568 __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset), | 4578 __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset), |
4569 Immediate(String::kEmptyHashField)); | 4579 Immediate(String::kEmptyHashField)); |
4570 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); | 4580 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); |
4571 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); | 4581 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); |
4572 __ movq(rax, rcx); | 4582 __ movq(rax, rcx); |
4573 __ IncrementCounter(counters->string_add_native(), 1); | 4583 __ IncrementCounter(counters->string_add_native(), 1); |
4574 __ ret(2 * kPointerSize); | 4584 __ ret(2 * kPointerSize); |
4575 __ bind(&non_ascii); | 4585 __ bind(&non_ascii); |
4576 // At least one of the strings is two-byte. Check whether it happens | 4586 // At least one of the strings is two-byte. Check whether it happens |
4577 // to contain only ascii characters. | 4587 // to contain only ascii characters. |
4578 // rcx: first instance type AND second instance type. | 4588 // rcx: first instance type AND second instance type. |
4579 // r8: first instance type. | 4589 // r8: first instance type. |
4580 // r9: second instance type. | 4590 // r9: second instance type. |
4581 __ testb(rcx, Immediate(kAsciiDataHintMask)); | 4591 __ testb(rcx, Immediate(kAsciiDataHintMask)); |
4582 __ j(not_zero, &ascii_data); | 4592 __ j(not_zero, &ascii_data); |
4583 __ xor_(r8, r9); | 4593 __ xor_(r8, r9); |
4584 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 4594 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |
4585 __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); | 4595 __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); |
4586 __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); | 4596 __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); |
4587 __ j(equal, &ascii_data); | 4597 __ j(equal, &ascii_data); |
4588 // Allocate a two byte cons string. | 4598 // Allocate a two byte cons string. |
4589 __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime); | 4599 __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime); |
4590 __ jmp(&allocated); | 4600 __ jmp(&allocated); |
4591 | 4601 |
4592 // Handle creating a flat result. First check that both strings are not | 4602 // We cannot encounter sliced strings or cons strings here since: |
4593 // external strings. | 4603 STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); |
| 4604 // Handle creating a flat result from either external or sequential strings. |
| 4605 // Locate the first characters' locations. |
4594 // rax: first string | 4606 // rax: first string |
4595 // rbx: length of resulting flat string as smi | 4607 // rbx: length of resulting flat string as smi |
4596 // rdx: second string | 4608 // rdx: second string |
4597 // r8: instance type of first string | 4609 // r8: instance type of first string |
4598 // r9: instance type of first string | 4610 // r9: instance type of first string |
| 4611 Label first_prepared, second_prepared; |
| 4612 Label first_is_sequential, second_is_sequential; |
4599 __ bind(&string_add_flat_result); | 4613 __ bind(&string_add_flat_result); |
| 4614 |
| 4615 __ SmiToInteger32(r14, FieldOperand(rax, SeqString::kLengthOffset)); |
| 4616 // r14: length of first string |
| 4617 STATIC_ASSERT(kSeqStringTag == 0); |
| 4618 __ testb(r8, Immediate(kStringRepresentationMask)); |
| 4619 __ j(zero, &first_is_sequential, Label::kNear); |
| 4620 // Rule out short external string and load string resource. |
| 4621 STATIC_ASSERT(kShortExternalStringTag != 0); |
| 4622 __ testb(r8, Immediate(kShortExternalStringMask)); |
| 4623 __ j(not_zero, &call_runtime); |
| 4624 __ movq(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset)); |
| 4625 __ jmp(&first_prepared, Label::kNear); |
| 4626 __ bind(&first_is_sequential); |
| 4627 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
| 4628 __ lea(rcx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
| 4629 __ bind(&first_prepared); |
| 4630 |
| 4631 // Check whether both strings have same encoding. |
| 4632 __ xorl(r8, r9); |
| 4633 __ testb(r8, Immediate(kStringEncodingMask)); |
| 4634 __ j(not_zero, &call_runtime); |
| 4635 |
| 4636 __ SmiToInteger32(r15, FieldOperand(rdx, SeqString::kLengthOffset)); |
| 4637 // r15: length of second string |
| 4638 STATIC_ASSERT(kSeqStringTag == 0); |
| 4639 __ testb(r9, Immediate(kStringRepresentationMask)); |
| 4640 __ j(zero, &second_is_sequential, Label::kNear); |
| 4641 // Rule out short external string and load string resource. |
| 4642 STATIC_ASSERT(kShortExternalStringTag != 0); |
| 4643 __ testb(r9, Immediate(kShortExternalStringMask)); |
| 4644 __ j(not_zero, &call_runtime); |
| 4645 __ movq(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset)); |
| 4646 __ jmp(&second_prepared, Label::kNear); |
| 4647 __ bind(&second_is_sequential); |
| 4648 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
| 4649 __ lea(rdx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); |
| 4650 __ bind(&second_prepared); |
| 4651 |
| 4652 Label non_ascii_string_add_flat_result; |
| 4653 // r9: instance type of second string |
| 4654 // First string and second string have the same encoding. |
| 4655 STATIC_ASSERT(kTwoByteStringTag == 0); |
4600 __ SmiToInteger32(rbx, rbx); | 4656 __ SmiToInteger32(rbx, rbx); |
4601 __ movl(rcx, r8); | 4657 __ testb(r9, Immediate(kStringEncodingMask)); |
4602 __ and_(rcx, Immediate(kStringRepresentationMask)); | |
4603 __ cmpl(rcx, Immediate(kExternalStringTag)); | |
4604 __ j(equal, &string_add_runtime); | |
4605 __ movl(rcx, r9); | |
4606 __ and_(rcx, Immediate(kStringRepresentationMask)); | |
4607 __ cmpl(rcx, Immediate(kExternalStringTag)); | |
4608 __ j(equal, &string_add_runtime); | |
4609 // We cannot encounter sliced strings here since: | |
4610 STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); | |
4611 // Now check if both strings are ascii strings. | |
4612 // rax: first string | |
4613 // rbx: length of resulting flat string | |
4614 // rdx: second string | |
4615 // r8: instance type of first string | |
4616 // r9: instance type of second string | |
4617 Label non_ascii_string_add_flat_result; | |
4618 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | |
4619 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
4620 __ testl(r8, Immediate(kStringEncodingMask)); | |
4621 __ j(zero, &non_ascii_string_add_flat_result); | 4658 __ j(zero, &non_ascii_string_add_flat_result); |
4622 __ testl(r9, Immediate(kStringEncodingMask)); | |
4623 __ j(zero, &string_add_runtime); | |
4624 | 4659 |
4625 __ bind(&make_flat_ascii_string); | 4660 __ bind(&make_flat_ascii_string); |
4626 // Both strings are ascii strings. As they are short they are both flat. | 4661 // Both strings are ascii strings. As they are short they are both flat. |
4627 __ AllocateAsciiString(rcx, rbx, rdi, r14, r11, &string_add_runtime); | 4662 __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime); |
4628 // rcx: result string | 4663 // rax: result string |
4629 __ movq(rbx, rcx); | |
4630 // Locate first character of result. | 4664 // Locate first character of result. |
4631 __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 4665 __ lea(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
4632 // Locate first character of first argument | 4666 // rcx: first char of first string |
4633 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); | 4667 // rbx: first character of result |
4634 __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 4668 // r14: length of first string |
4635 // rax: first char of first argument | 4669 StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, true); |
4636 // rbx: result string | 4670 // rbx: next character of result |
4637 // rcx: first character of result | 4671 // rdx: first char of second string |
4638 // rdx: second string | 4672 // r15: length of second string |
4639 // rdi: length of first argument | 4673 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, true); |
4640 StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, true); | |
4641 // Locate first character of second argument. | |
4642 __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset)); | |
4643 __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
4644 // rbx: result string | |
4645 // rcx: next character of result | |
4646 // rdx: first char of second argument | |
4647 // rdi: length of second argument | |
4648 StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, true); | |
4649 __ movq(rax, rbx); | |
4650 __ IncrementCounter(counters->string_add_native(), 1); | 4674 __ IncrementCounter(counters->string_add_native(), 1); |
4651 __ ret(2 * kPointerSize); | 4675 __ ret(2 * kPointerSize); |
4652 | 4676 |
4653 // Handle creating a flat two byte result. | |
4654 // rax: first string - known to be two byte | |
4655 // rbx: length of resulting flat string | |
4656 // rdx: second string | |
4657 // r8: instance type of first string | |
4658 // r9: instance type of first string | |
4659 __ bind(&non_ascii_string_add_flat_result); | 4677 __ bind(&non_ascii_string_add_flat_result); |
4660 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | 4678 // Both strings are ascii strings. As they are short they are both flat. |
4661 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 4679 __ AllocateTwoByteString(rax, rbx, rdi, r8, r9, &call_runtime); |
4662 __ and_(r9, Immediate(kStringEncodingMask)); | 4680 // rax: result string |
4663 __ j(not_zero, &string_add_runtime); | |
4664 // Both strings are two byte strings. As they are short they are both | |
4665 // flat. | |
4666 __ AllocateTwoByteString(rcx, rbx, rdi, r14, r11, &string_add_runtime); | |
4667 // rcx: result string | |
4668 __ movq(rbx, rcx); | |
4669 // Locate first character of result. | 4681 // Locate first character of result. |
4670 __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 4682 __ lea(rbx, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); |
4671 // Locate first character of first argument. | 4683 // rcx: first char of first string |
4672 __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset)); | 4684 // rbx: first character of result |
4673 __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 4685 // r14: length of first string |
4674 // rax: first char of first argument | 4686 StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, false); |
4675 // rbx: result string | 4687 // rbx: next character of result |
4676 // rcx: first character of result | 4688 // rdx: first char of second string |
4677 // rdx: second argument | 4689 // r15: length of second string |
4678 // rdi: length of first argument | 4690 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); |
4679 StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, false); | |
4680 // Locate first character of second argument. | |
4681 __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset)); | |
4682 __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
4683 // rbx: result string | |
4684 // rcx: next character of result | |
4685 // rdx: first char of second argument | |
4686 // rdi: length of second argument | |
4687 StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false); | |
4688 __ movq(rax, rbx); | |
4689 __ IncrementCounter(counters->string_add_native(), 1); | 4691 __ IncrementCounter(counters->string_add_native(), 1); |
4690 __ ret(2 * kPointerSize); | 4692 __ ret(2 * kPointerSize); |
4691 | 4693 |
4692 // Just jump to runtime to add the two strings. | 4694 // Just jump to runtime to add the two strings. |
4693 __ bind(&string_add_runtime); | 4695 __ bind(&call_runtime); |
4694 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 4696 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
4695 | 4697 |
4696 if (call_builtin.is_linked()) { | 4698 if (call_builtin.is_linked()) { |
4697 __ bind(&call_builtin); | 4699 __ bind(&call_builtin); |
4698 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 4700 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
4699 } | 4701 } |
4700 } | 4702 } |
4701 | 4703 |
4702 | 4704 |
4703 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | 4705 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, |
(...skipping 1525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6229 xmm0, | 6231 xmm0, |
6230 &slow_elements); | 6232 &slow_elements); |
6231 __ ret(0); | 6233 __ ret(0); |
6232 } | 6234 } |
6233 | 6235 |
6234 #undef __ | 6236 #undef __ |
6235 | 6237 |
6236 } } // namespace v8::internal | 6238 } } // namespace v8::internal |
6237 | 6239 |
6238 #endif // V8_TARGET_ARCH_X64 | 6240 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |