| Index: src/x64/code-stubs-x64.cc
|
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
|
| index 1e68bdf8e8f52eb28ea096f84c338a4ac1b42206..6617dfaecc4b8b8ee675cdd1747aa3b1d0c0f546 100644
|
| --- a/src/x64/code-stubs-x64.cc
|
| +++ b/src/x64/code-stubs-x64.cc
|
| @@ -350,7 +350,7 @@ void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
|
| }
|
|
|
|
|
| -void NewStringAddStub::InitializeInterfaceDescriptor(
|
| +void StringAddStub::InitializeInterfaceDescriptor(
|
| Isolate* isolate,
|
| CodeStubInterfaceDescriptor* descriptor) {
|
| static Register registers[] = { rdx, rax };
|
| @@ -3244,340 +3244,6 @@ void StringCharFromCodeGenerator::GenerateSlow(
|
| }
|
|
|
|
|
| -void StringAddStub::Generate(MacroAssembler* masm) {
|
| - Label call_runtime, call_builtin;
|
| - Builtins::JavaScript builtin_id = Builtins::ADD;
|
| -
|
| - // Load the two arguments.
|
| - StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
|
| - __ movp(rax, args.GetArgumentOperand(0)); // First argument (left).
|
| - __ movp(rdx, args.GetArgumentOperand(1)); // Second argument (right).
|
| -
|
| - // Make sure that both arguments are strings if not known in advance.
|
| - // Otherwise, at least one of the arguments is definitely a string,
|
| - // and we convert the one that is not known to be a string.
|
| - if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
|
| - ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT);
|
| - ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT);
|
| - __ JumpIfSmi(rax, &call_runtime);
|
| - __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
|
| - __ j(above_equal, &call_runtime);
|
| -
|
| - // First argument is a a string, test second.
|
| - __ JumpIfSmi(rdx, &call_runtime);
|
| - __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
|
| - __ j(above_equal, &call_runtime);
|
| - } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
|
| - ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0);
|
| - GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi,
|
| - &call_builtin);
|
| - builtin_id = Builtins::STRING_ADD_RIGHT;
|
| - } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
|
| - ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0);
|
| - GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi,
|
| - &call_builtin);
|
| - builtin_id = Builtins::STRING_ADD_LEFT;
|
| - }
|
| -
|
| - // 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;
|
| - __ movp(rcx, FieldOperand(rdx, String::kLengthOffset));
|
| - __ SmiTest(rcx);
|
| - __ j(not_zero, &second_not_zero_length, Label::kNear);
|
| - // Second string is empty, result is first string which is already in rax.
|
| - Counters* counters = masm->isolate()->counters();
|
| - __ IncrementCounter(counters->string_add_native(), 1);
|
| - __ ret(2 * kPointerSize);
|
| - __ bind(&second_not_zero_length);
|
| - __ movp(rbx, FieldOperand(rax, String::kLengthOffset));
|
| - __ SmiTest(rbx);
|
| - __ j(not_zero, &both_not_zero_length, Label::kNear);
|
| - // First string is empty, result is second string which is in rdx.
|
| - __ movp(rax, rdx);
|
| - __ IncrementCounter(counters->string_add_native(), 1);
|
| - __ ret(2 * kPointerSize);
|
| -
|
| - // Both strings are non-empty.
|
| - // rax: first string
|
| - // rbx: length of first string
|
| - // rcx: length of second string
|
| - // rdx: second string
|
| - // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS)
|
| - // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS)
|
| - Label string_add_flat_result, longer_than_two;
|
| - __ bind(&both_not_zero_length);
|
| -
|
| - // If arguments where known to be strings, maps are not loaded to r8 and r9
|
| - // by the code above.
|
| - if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
|
| - __ movp(r8, FieldOperand(rax, HeapObject::kMapOffset));
|
| - __ movp(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));
|
| -
|
| - // Look at the length of the result of adding the two strings.
|
| - STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
|
| - __ SmiAdd(rbx, rbx, rcx);
|
| - // Use the string table when adding two one character strings, as it
|
| - // helps later optimizations to return an internalized string here.
|
| - __ SmiCompare(rbx, Smi::FromInt(2));
|
| - __ j(not_equal, &longer_than_two);
|
| -
|
| - // Check that both strings are non-external ASCII strings.
|
| - __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
|
| - &call_runtime);
|
| -
|
| - // Get the two characters forming the sub string.
|
| - __ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize));
|
| - __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize));
|
| -
|
| - // Try to lookup two character string in string table. If it is not found
|
| - // just allocate a new one.
|
| - Label make_two_character_string, make_flat_ascii_string;
|
| - StringHelper::GenerateTwoCharacterStringTableProbe(
|
| - masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string);
|
| - __ IncrementCounter(counters->string_add_native(), 1);
|
| - __ ret(2 * kPointerSize);
|
| -
|
| - __ bind(&make_two_character_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, SeqOneByteString::kHeaderSize));
|
| - __ shll(rcx, Immediate(kBitsPerByte));
|
| - __ orl(rbx, rcx);
|
| - // Write both characters to the new string.
|
| - __ movw(FieldOperand(rax, SeqOneByteString::kHeaderSize), rbx);
|
| - __ IncrementCounter(counters->string_add_native(), 1);
|
| - __ ret(2 * kPointerSize);
|
| -
|
| - __ bind(&longer_than_two);
|
| - // Check if resulting string will be flat.
|
| - __ SmiCompare(rbx, Smi::FromInt(ConsString::kMinLength));
|
| - __ j(below, &string_add_flat_result);
|
| - // Handle exceptionally long strings in the runtime system.
|
| - STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
|
| - __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength));
|
| - __ 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.
|
| - // rax: first string
|
| - // rbx: length of resulting flat string
|
| - // rdx: second string
|
| - // r8: instance type of first string
|
| - // r9: instance type of second string
|
| - Label non_ascii, allocated, ascii_data;
|
| - __ movl(rcx, r8);
|
| - __ and_(rcx, r9);
|
| - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
|
| - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
|
| - __ testl(rcx, Immediate(kStringEncodingMask));
|
| - __ j(zero, &non_ascii);
|
| - __ bind(&ascii_data);
|
| - // Allocate an ASCII cons string.
|
| - __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime);
|
| - __ bind(&allocated);
|
| - // Fill the fields of the cons string.
|
| - __ movp(FieldOperand(rcx, ConsString::kLengthOffset), rbx);
|
| - __ movp(FieldOperand(rcx, ConsString::kHashFieldOffset),
|
| - Immediate(String::kEmptyHashField));
|
| -
|
| - Label skip_write_barrier, after_writing;
|
| - ExternalReference high_promotion_mode = ExternalReference::
|
| - new_space_high_promotion_mode_active_address(masm->isolate());
|
| - __ Load(rbx, high_promotion_mode);
|
| - __ testb(rbx, Immediate(1));
|
| - __ j(zero, &skip_write_barrier);
|
| -
|
| - __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax);
|
| - __ RecordWriteField(rcx,
|
| - ConsString::kFirstOffset,
|
| - rax,
|
| - rbx,
|
| - kDontSaveFPRegs);
|
| - __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
|
| - __ RecordWriteField(rcx,
|
| - ConsString::kSecondOffset,
|
| - rdx,
|
| - rbx,
|
| - kDontSaveFPRegs);
|
| - __ jmp(&after_writing);
|
| -
|
| - __ bind(&skip_write_barrier);
|
| - __ movp(FieldOperand(rcx, ConsString::kFirstOffset), rax);
|
| - __ movp(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
|
| -
|
| - __ bind(&after_writing);
|
| -
|
| - __ movp(rax, rcx);
|
| - __ IncrementCounter(counters->string_add_native(), 1);
|
| - __ ret(2 * kPointerSize);
|
| - __ bind(&non_ascii);
|
| - // At least one of the strings is two-byte. Check whether it happens
|
| - // to contain only one byte characters.
|
| - // rcx: first instance type AND second instance type.
|
| - // r8: first instance type.
|
| - // r9: second instance type.
|
| - __ testb(rcx, Immediate(kOneByteDataHintMask));
|
| - __ j(not_zero, &ascii_data);
|
| - __ xor_(r8, r9);
|
| - STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
|
| - __ andb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag));
|
| - __ cmpb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag));
|
| - __ j(equal, &ascii_data);
|
| - // Allocate a two byte cons string.
|
| - __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime);
|
| - __ jmp(&allocated);
|
| -
|
| - // We cannot encounter sliced strings or cons strings here since:
|
| - STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
|
| - // 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(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);
|
| - __ movp(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset));
|
| - __ jmp(&first_prepared, Label::kNear);
|
| - __ bind(&first_is_sequential);
|
| - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
| - __ lea(rcx, FieldOperand(rax, SeqOneByteString::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);
|
| - __ movp(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset));
|
| - __ jmp(&second_prepared, Label::kNear);
|
| - __ bind(&second_is_sequential);
|
| - STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
| - __ lea(rdx, FieldOperand(rdx, SeqOneByteString::kHeaderSize));
|
| - __ bind(&second_prepared);
|
| -
|
| - Label non_ascii_string_add_flat_result;
|
| - // 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);
|
| -
|
| - __ bind(&make_flat_ascii_string);
|
| - // Both strings are ASCII strings. As they are short they are both flat.
|
| - __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime);
|
| - // rax: result string
|
| - // Locate first character of result.
|
| - __ lea(rbx, FieldOperand(rax, SeqOneByteString::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);
|
| -
|
| - __ bind(&non_ascii_string_add_flat_result);
|
| - // 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.
|
| - __ 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(&call_runtime);
|
| - __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
|
| -
|
| - if (call_builtin.is_linked()) {
|
| - __ bind(&call_builtin);
|
| - __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
|
| - }
|
| -}
|
| -
|
| -
|
| -void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
|
| - __ push(rax);
|
| - __ push(rdx);
|
| -}
|
| -
|
| -
|
| -void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm,
|
| - Register temp) {
|
| - __ PopReturnAddressTo(temp);
|
| - __ pop(rdx);
|
| - __ pop(rax);
|
| - __ PushReturnAddressFrom(temp);
|
| -}
|
| -
|
| -
|
| -void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
|
| - int stack_offset,
|
| - Register arg,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Register scratch3,
|
| - Label* slow) {
|
| - // First check if the argument is already a string.
|
| - Label not_string, done;
|
| - __ JumpIfSmi(arg, ¬_string);
|
| - __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
|
| - __ j(below, &done);
|
| -
|
| - // Check the number to string cache.
|
| - __ bind(¬_string);
|
| - // Puts the cached result into scratch1.
|
| - __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow);
|
| - __ movp(arg, scratch1);
|
| - __ movp(Operand(rsp, stack_offset), arg);
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
|
| Register dest,
|
| Register src,
|
|
|