Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 3430) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -4051,7 +4051,8 @@ |
Load(args->at(0)); |
Load(args->at(1)); |
- Result answer = frame_->CallRuntime(Runtime::kStringAdd, 2); |
+ StringAddStub stub(NO_STRING_ADD_FLAGS); |
+ Result answer = frame_->CallStub(&stub, 2); |
frame_->Push(&answer); |
} |
@@ -7796,8 +7797,8 @@ |
__ j(above_equal, &string1); |
// First and second argument are strings. |
- Runtime::Function* f = Runtime::FunctionForId(Runtime::kStringAdd); |
- __ TailCallRuntime(ExternalReference(f), 2, f->result_size); |
+ StringAddStub stub(NO_STRING_CHECK_IN_STUB); |
+ __ TailCallStub(&stub); |
// Only first argument is a string. |
__ bind(&string1); |
@@ -7880,6 +7881,234 @@ |
return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
} |
+ |
+void StringAddStub::Generate(MacroAssembler* masm) { |
+ Label string_add_runtime; |
+ |
+ // Load the two arguments. |
+ __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. |
+ __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. |
+ |
+ // Make sure that both arguments are strings if not known in advance. |
+ if (string_check_) { |
+ Condition is_smi; |
+ is_smi = masm->CheckSmi(rax); |
+ __ j(is_smi, &string_add_runtime); |
+ __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); |
+ __ j(above_equal, &string_add_runtime); |
+ |
+ // First argument is a a string, test second. |
+ is_smi = masm->CheckSmi(rdx); |
+ __ j(is_smi, &string_add_runtime); |
+ __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
+ __ j(above_equal, &string_add_runtime); |
+ } |
+ |
+ // Both arguments are strings. |
+ // rax: first string |
+ // rdx: second string |
+ // Check if either of the strings are empty. In that case return the other. |
+ Label second_not_zero_length, both_not_zero_length; |
+ __ movl(rcx, FieldOperand(rdx, String::kLengthOffset)); |
+ __ testl(rcx, rcx); |
+ __ j(not_zero, &second_not_zero_length); |
+ // Second string is empty, result is first string which is already in rax. |
+ __ IncrementCounter(&Counters::string_add_native, 1); |
+ __ ret(2 * kPointerSize); |
+ __ bind(&second_not_zero_length); |
+ __ movl(rbx, FieldOperand(rax, String::kLengthOffset)); |
+ __ testl(rbx, rbx); |
+ __ j(not_zero, &both_not_zero_length); |
+ // First string is empty, result is second string which is in rdx. |
+ __ movq(rax, rdx); |
+ __ IncrementCounter(&Counters::string_add_native, 1); |
+ __ ret(2 * kPointerSize); |
+ |
+ // Both strings are non-empty. |
+ // rax: first string |
+ // rbx: length of first string |
+ // ecx: length of second string |
+ // edx: second string |
+ // r8: instance type of first string if string check was performed above |
+ // r9: instance type of first string if string check was performed above |
+ Label string_add_flat_result; |
+ __ bind(&both_not_zero_length); |
+ // Look at the length of the result of adding the two strings. |
+ __ addl(rbx, rcx); |
+ // Use the runtime system when adding two one character strings, as it |
+ // contains optimizations for this specific case using the symbol table. |
+ __ cmpl(rbx, Immediate(2)); |
+ __ j(equal, &string_add_runtime); |
+ // If arguments where known to be strings, maps are not loaded to r8 and r9 |
+ // by the code above. |
+ if (!string_check_) { |
+ __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
+ __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
+ } |
+ // Get the instance types of the two strings as they will be needed soon. |
+ __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
+ __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
+ // Check if resulting string will be flat. |
+ __ cmpl(rbx, Immediate(String::kMinNonFlatLength)); |
+ __ j(below, &string_add_flat_result); |
+ // Handle exceptionally long strings in the runtime system. |
+ ASSERT((String::kMaxLength & 0x80000000) == 0); |
+ __ cmpl(rbx, Immediate(String::kMaxLength)); |
+ __ j(above, &string_add_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. |
+ // rax: first string |
+ // ebx: length of resulting flat string |
+ // rdx: second string |
+ // r8: instance type of first string |
+ // r9: instance type of second string |
+ Label non_ascii, allocated; |
+ __ movl(rcx, r8); |
+ __ and_(rcx, r9); |
+ ASSERT(kStringEncodingMask == kAsciiStringTag); |
+ __ testl(rcx, Immediate(kAsciiStringTag)); |
+ __ j(zero, &non_ascii); |
+ // Allocate an acsii cons string. |
+ __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime); |
+ __ bind(&allocated); |
+ // Fill the fields of the cons string. |
+ __ movl(FieldOperand(rcx, ConsString::kLengthOffset), rbx); |
+ __ movl(FieldOperand(rcx, ConsString::kHashFieldOffset), |
+ Immediate(String::kEmptyHashField)); |
+ __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); |
+ __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); |
+ __ movq(rax, rcx); |
+ __ IncrementCounter(&Counters::string_add_native, 1); |
+ __ ret(2 * kPointerSize); |
+ __ bind(&non_ascii); |
+ // Allocate a two byte cons string. |
+ __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime); |
+ __ jmp(&allocated); |
+ |
+ // Handle creating a flat result. First check that both strings are not |
+ // external strings. |
+ // rax: first string |
+ // ebx: length of resulting flat string |
+ // rdx: second string |
+ // r8: instance type of first string |
+ // r9: instance type of first string |
+ __ bind(&string_add_flat_result); |
+ __ 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); |
+ // Now check if both strings are ascii strings. |
+ // rax: first string |
+ // ebx: length of resulting flat string |
+ // rdx: second string |
+ // r8: instance type of first string |
+ // r9: instance type of second string |
+ Label non_ascii_string_add_flat_result; |
+ ASSERT(kStringEncodingMask == kAsciiStringTag); |
+ __ testl(r8, Immediate(kAsciiStringTag)); |
+ __ j(zero, &non_ascii_string_add_flat_result); |
+ __ testl(r9, Immediate(kAsciiStringTag)); |
+ __ j(zero, &string_add_runtime); |
+ // Both strings are ascii strings. As they are short they are both flat. |
+ __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime); |
+ // rcx: result string |
+ __ movq(rbx, rcx); |
+ // Locate first character of result. |
+ __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ // Locate first character of first argument |
+ __ movl(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 |
+ GenerateCopyCharacters(masm, rcx, rax, rdi, true); |
+ // Locate first character of second argument. |
+ __ movl(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 |
+ GenerateCopyCharacters(masm, rcx, rdx, rdi, true); |
+ __ movq(rax, rbx); |
+ __ 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); |
+ __ and_(r9, Immediate(kAsciiStringTag)); |
+ __ 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, r15, &string_add_runtime); |
+ // rcx: result string |
+ __ movq(rbx, rcx); |
+ // Locate first character of result. |
+ __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
+ // Locate first character of first argument. |
+ __ movl(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 |
+ GenerateCopyCharacters(masm, rcx, rax, rdi, false); |
+ // Locate first character of second argument. |
+ __ movl(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 |
+ GenerateCopyCharacters(masm, rcx, rdx, rdi, false); |
+ __ movq(rax, rbx); |
+ __ IncrementCounter(&Counters::string_add_native, 1); |
+ __ ret(2 * kPointerSize); |
+ |
+ // Just jump to runtime to add the two strings. |
+ __ bind(&string_add_runtime); |
+ __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); |
+} |
+ |
+ |
+void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm, |
+ Register dest, |
+ Register src, |
+ Register count, |
+ bool ascii) { |
+ Label loop; |
+ __ bind(&loop); |
+ // This loop just copies one character at a time, as it is only used for very |
+ // short strings. |
+ if (ascii) { |
+ __ movb(kScratchRegister, Operand(src, 0)); |
+ __ movb(Operand(dest, 0), kScratchRegister); |
+ __ addq(src, Immediate(1)); |
+ __ addq(dest, Immediate(1)); |
+ } else { |
+ __ movzxwl(kScratchRegister, Operand(src, 0)); |
+ __ movw(Operand(dest, 0), kScratchRegister); |
+ __ addq(src, Immediate(2)); |
+ __ addq(dest, Immediate(2)); |
+ } |
+ __ subl(count, Immediate(1)); |
+ __ j(not_zero, &loop); |
+} |
+ |
+ |
#undef __ |
#define __ masm. |