| 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 |