| Index: src/x64/code-stubs-x64.cc
|
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
|
| index ec37760b1da544102d1a1de83c104d9bf97a9097..1d67bae60ad70cb1af0b96c391c1e72e75d579a8 100644
|
| --- a/src/x64/code-stubs-x64.cc
|
| +++ b/src/x64/code-stubs-x64.cc
|
| @@ -4434,7 +4434,7 @@ void StringCharAtGenerator::GenerateSlow(
|
|
|
|
|
| void StringAddStub::Generate(MacroAssembler* masm) {
|
| - Label string_add_runtime, call_builtin;
|
| + Label call_runtime, call_builtin;
|
| Builtins::JavaScript builtin_id = Builtins::ADD;
|
|
|
| // Load the two arguments.
|
| @@ -4443,14 +4443,14 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
|
|
| // Make sure that both arguments are strings if not known in advance.
|
| if (flags_ == NO_STRING_ADD_FLAGS) {
|
| - __ JumpIfSmi(rax, &string_add_runtime);
|
| + __ JumpIfSmi(rax, &call_runtime);
|
| __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
|
| - __ j(above_equal, &string_add_runtime);
|
| + __ j(above_equal, &call_runtime);
|
|
|
| // First argument is a a string, test second.
|
| - __ JumpIfSmi(rdx, &string_add_runtime);
|
| + __ JumpIfSmi(rdx, &call_runtime);
|
| __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
|
| - __ j(above_equal, &string_add_runtime);
|
| + __ j(above_equal, &call_runtime);
|
| } else {
|
| // Here at least one of the arguments is definitely a string.
|
| // We convert the one that is not known to be a string.
|
| @@ -4518,7 +4518,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
|
|
| // Check that both strings are non-external ascii strings.
|
| __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
|
| - &string_add_runtime);
|
| + &call_runtime);
|
|
|
| // Get the two characters forming the sub string.
|
| __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
|
| @@ -4533,8 +4533,18 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
| __ ret(2 * kPointerSize);
|
|
|
| __ bind(&make_two_character_string);
|
| - __ Set(rbx, 2);
|
| - __ jmp(&make_flat_ascii_string);
|
| + __ Set(rdi, 2);
|
| + __ AllocateAsciiString(rax, rdi, r8, r9, r11, &call_runtime);
|
| + // rbx - first byte: first character
|
| + // rbx - second byte: *maybe* second character
|
| + // Make sure that the second byte of rbx contains the second character.
|
| + __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize));
|
| + __ shll(rcx, Immediate(kBitsPerByte));
|
| + __ orl(rbx, rcx);
|
| + // Write both characters to the new string.
|
| + __ movw(FieldOperand(rax, SeqAsciiString::kHeaderSize), rbx);
|
| + __ IncrementCounter(counters->string_add_native(), 1);
|
| + __ ret(2 * kPointerSize);
|
|
|
| __ bind(&longer_than_two);
|
| // Check if resulting string will be flat.
|
| @@ -4543,7 +4553,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
| // Handle exceptionally long strings in the runtime system.
|
| STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
|
| __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength));
|
| - __ j(above, &string_add_runtime);
|
| + __ j(above, &call_runtime);
|
|
|
| // If result is not supposed to be flat, allocate a cons string object. If
|
| // both strings are ascii the result is an ascii cons string.
|
| @@ -4561,7 +4571,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
| __ j(zero, &non_ascii);
|
| __ bind(&ascii_data);
|
| // Allocate an acsii cons string.
|
| - __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime);
|
| + __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime);
|
| __ bind(&allocated);
|
| // Fill the fields of the cons string.
|
| __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx);
|
| @@ -4586,111 +4596,103 @@ void StringAddStub::Generate(MacroAssembler* masm) {
|
| __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag));
|
| __ j(equal, &ascii_data);
|
| // Allocate a two byte cons string.
|
| - __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime);
|
| + __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime);
|
| __ jmp(&allocated);
|
|
|
| - // Handle creating a flat result. First check that both strings are not
|
| - // external strings.
|
| + // We cannot encounter sliced strings or cons strings here since:
|
| + STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength);
|
| + // Handle creating a flat result from either external or sequential strings.
|
| + // Locate the first characters' locations.
|
| // rax: first string
|
| // rbx: length of resulting flat string as smi
|
| // rdx: second string
|
| // r8: instance type of first string
|
| // r9: instance type of first string
|
| + Label first_prepared, second_prepared;
|
| + Label first_is_sequential, second_is_sequential;
|
| __ bind(&string_add_flat_result);
|
| - __ SmiToInteger32(rbx, rbx);
|
| - __ movl(rcx, r8);
|
| - __ and_(rcx, Immediate(kStringRepresentationMask));
|
| - __ cmpl(rcx, Immediate(kExternalStringTag));
|
| - __ j(equal, &string_add_runtime);
|
| - __ movl(rcx, r9);
|
| - __ and_(rcx, Immediate(kStringRepresentationMask));
|
| - __ cmpl(rcx, Immediate(kExternalStringTag));
|
| - __ j(equal, &string_add_runtime);
|
| - // We cannot encounter sliced strings here since:
|
| - STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength);
|
| - // Now check if both strings are ascii strings.
|
| - // rax: first string
|
| - // rbx: length of resulting flat string
|
| - // rdx: second string
|
| - // r8: instance type of first string
|
| - // r9: instance type of second string
|
| +
|
| + __ SmiToInteger32(r14, FieldOperand(rax, SeqString::kLengthOffset));
|
| + // r14: length of first string
|
| + STATIC_ASSERT(kSeqStringTag == 0);
|
| + __ testb(r8, Immediate(kStringRepresentationMask));
|
| + __ j(zero, &first_is_sequential, Label::kNear);
|
| + // Rule out short external string and load string resource.
|
| + STATIC_ASSERT(kShortExternalStringTag != 0);
|
| + __ testb(r8, Immediate(kShortExternalStringMask));
|
| + __ j(not_zero, &call_runtime);
|
| + __ movq(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset));
|
| + __ jmp(&first_prepared, Label::kNear);
|
| + __ bind(&first_is_sequential);
|
| + STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
| + __ lea(rcx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
|
| + __ bind(&first_prepared);
|
| +
|
| + // Check whether both strings have same encoding.
|
| + __ xorl(r8, r9);
|
| + __ testb(r8, Immediate(kStringEncodingMask));
|
| + __ j(not_zero, &call_runtime);
|
| +
|
| + __ SmiToInteger32(r15, FieldOperand(rdx, SeqString::kLengthOffset));
|
| + // r15: length of second string
|
| + STATIC_ASSERT(kSeqStringTag == 0);
|
| + __ testb(r9, Immediate(kStringRepresentationMask));
|
| + __ j(zero, &second_is_sequential, Label::kNear);
|
| + // Rule out short external string and load string resource.
|
| + STATIC_ASSERT(kShortExternalStringTag != 0);
|
| + __ testb(r9, Immediate(kShortExternalStringMask));
|
| + __ j(not_zero, &call_runtime);
|
| + __ movq(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset));
|
| + __ jmp(&second_prepared, Label::kNear);
|
| + __ bind(&second_is_sequential);
|
| + STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
| + __ lea(rdx, FieldOperand(rdx, SeqAsciiString::kHeaderSize));
|
| + __ bind(&second_prepared);
|
| +
|
| Label non_ascii_string_add_flat_result;
|
| - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
|
| - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
|
| - __ testl(r8, Immediate(kStringEncodingMask));
|
| + // r9: instance type of second string
|
| + // First string and second string have the same encoding.
|
| + STATIC_ASSERT(kTwoByteStringTag == 0);
|
| + __ SmiToInteger32(rbx, rbx);
|
| + __ testb(r9, Immediate(kStringEncodingMask));
|
| __ j(zero, &non_ascii_string_add_flat_result);
|
| - __ testl(r9, Immediate(kStringEncodingMask));
|
| - __ j(zero, &string_add_runtime);
|
|
|
| __ bind(&make_flat_ascii_string);
|
| // Both strings are ascii strings. As they are short they are both flat.
|
| - __ AllocateAsciiString(rcx, rbx, rdi, r14, r11, &string_add_runtime);
|
| - // rcx: result string
|
| - __ movq(rbx, rcx);
|
| + __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime);
|
| + // rax: result string
|
| // Locate first character of result.
|
| - __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
|
| - // Locate first character of first argument
|
| - __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
|
| - __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
|
| - // rax: first char of first argument
|
| - // rbx: result string
|
| - // rcx: first character of result
|
| - // rdx: second string
|
| - // rdi: length of first argument
|
| - StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, true);
|
| - // Locate first character of second argument.
|
| - __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset));
|
| - __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
|
| - // rbx: result string
|
| - // rcx: next character of result
|
| - // rdx: first char of second argument
|
| - // rdi: length of second argument
|
| - StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, true);
|
| - __ movq(rax, rbx);
|
| + __ lea(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
|
| + // rcx: first char of first string
|
| + // rbx: first character of result
|
| + // r14: length of first string
|
| + StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, true);
|
| + // rbx: next character of result
|
| + // rdx: first char of second string
|
| + // r15: length of second string
|
| + StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, true);
|
| __ IncrementCounter(counters->string_add_native(), 1);
|
| __ ret(2 * kPointerSize);
|
|
|
| - // Handle creating a flat two byte result.
|
| - // rax: first string - known to be two byte
|
| - // rbx: length of resulting flat string
|
| - // rdx: second string
|
| - // r8: instance type of first string
|
| - // r9: instance type of first string
|
| __ bind(&non_ascii_string_add_flat_result);
|
| - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
|
| - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
|
| - __ and_(r9, Immediate(kStringEncodingMask));
|
| - __ j(not_zero, &string_add_runtime);
|
| - // Both strings are two byte strings. As they are short they are both
|
| - // flat.
|
| - __ AllocateTwoByteString(rcx, rbx, rdi, r14, r11, &string_add_runtime);
|
| - // rcx: result string
|
| - __ movq(rbx, rcx);
|
| + // Both strings are ascii strings. As they are short they are both flat.
|
| + __ AllocateTwoByteString(rax, rbx, rdi, r8, r9, &call_runtime);
|
| + // rax: result string
|
| // Locate first character of result.
|
| - __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
|
| - // Locate first character of first argument.
|
| - __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
|
| - __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
|
| - // rax: first char of first argument
|
| - // rbx: result string
|
| - // rcx: first character of result
|
| - // rdx: second argument
|
| - // rdi: length of first argument
|
| - StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, false);
|
| - // Locate first character of second argument.
|
| - __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset));
|
| - __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
|
| - // rbx: result string
|
| - // rcx: next character of result
|
| - // rdx: first char of second argument
|
| - // rdi: length of second argument
|
| - StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false);
|
| - __ movq(rax, rbx);
|
| + __ lea(rbx, FieldOperand(rax, SeqTwoByteString::kHeaderSize));
|
| + // rcx: first char of first string
|
| + // rbx: first character of result
|
| + // r14: length of first string
|
| + StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, false);
|
| + // rbx: next character of result
|
| + // rdx: first char of second string
|
| + // r15: length of second string
|
| + StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false);
|
| __ IncrementCounter(counters->string_add_native(), 1);
|
| __ ret(2 * kPointerSize);
|
|
|
| // Just jump to runtime to add the two strings.
|
| - __ bind(&string_add_runtime);
|
| + __ bind(&call_runtime);
|
| __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
|
|
|
| if (call_builtin.is_linked()) {
|
|
|