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 5456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5467 | 5467 |
5468 void StringCharAtGenerator::GenerateSlow( | 5468 void StringCharAtGenerator::GenerateSlow( |
5469 MacroAssembler* masm, | 5469 MacroAssembler* masm, |
5470 const RuntimeCallHelper& call_helper) { | 5470 const RuntimeCallHelper& call_helper) { |
5471 char_code_at_generator_.GenerateSlow(masm, call_helper); | 5471 char_code_at_generator_.GenerateSlow(masm, call_helper); |
5472 char_from_code_generator_.GenerateSlow(masm, call_helper); | 5472 char_from_code_generator_.GenerateSlow(masm, call_helper); |
5473 } | 5473 } |
5474 | 5474 |
5475 | 5475 |
5476 void StringAddStub::Generate(MacroAssembler* masm) { | 5476 void StringAddStub::Generate(MacroAssembler* masm) { |
5477 Label string_add_runtime, call_builtin; | 5477 Label call_runtime, call_builtin; |
5478 Builtins::JavaScript builtin_id = Builtins::ADD; | 5478 Builtins::JavaScript builtin_id = Builtins::ADD; |
5479 | 5479 |
5480 // Load the two arguments. | 5480 // Load the two arguments. |
5481 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 5481 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
5482 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 5482 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
5483 | 5483 |
5484 // Make sure that both arguments are strings if not known in advance. | 5484 // Make sure that both arguments are strings if not known in advance. |
5485 if (flags_ == NO_STRING_ADD_FLAGS) { | 5485 if (flags_ == NO_STRING_ADD_FLAGS) { |
5486 __ JumpIfSmi(eax, &string_add_runtime); | 5486 __ JumpIfSmi(eax, &call_runtime); |
5487 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); | 5487 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); |
5488 __ j(above_equal, &string_add_runtime); | 5488 __ j(above_equal, &call_runtime); |
5489 | 5489 |
5490 // First argument is a a string, test second. | 5490 // First argument is a a string, test second. |
5491 __ JumpIfSmi(edx, &string_add_runtime); | 5491 __ JumpIfSmi(edx, &call_runtime); |
5492 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); | 5492 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); |
5493 __ j(above_equal, &string_add_runtime); | 5493 __ j(above_equal, &call_runtime); |
5494 } else { | 5494 } else { |
5495 // Here at least one of the arguments is definitely a string. | 5495 // Here at least one of the arguments is definitely a string. |
5496 // We convert the one that is not known to be a string. | 5496 // We convert the one that is not known to be a string. |
5497 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 5497 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { |
5498 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 5498 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); |
5499 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, | 5499 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, |
5500 &call_builtin); | 5500 &call_builtin); |
5501 builtin_id = Builtins::STRING_ADD_RIGHT; | 5501 builtin_id = Builtins::STRING_ADD_RIGHT; |
5502 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 5502 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { |
5503 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 5503 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); |
(...skipping 30 matching lines...) Expand all Loading... |
5534 // eax: first string | 5534 // eax: first string |
5535 // ebx: length of first string as a smi | 5535 // ebx: length of first string as a smi |
5536 // ecx: length of second string as a smi | 5536 // ecx: length of second string as a smi |
5537 // edx: second string | 5537 // edx: second string |
5538 // Look at the length of the result of adding the two strings. | 5538 // Look at the length of the result of adding the two strings. |
5539 Label string_add_flat_result, longer_than_two; | 5539 Label string_add_flat_result, longer_than_two; |
5540 __ bind(&both_not_zero_length); | 5540 __ bind(&both_not_zero_length); |
5541 __ add(ebx, ecx); | 5541 __ add(ebx, ecx); |
5542 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); | 5542 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); |
5543 // Handle exceptionally long strings in the runtime system. | 5543 // Handle exceptionally long strings in the runtime system. |
5544 __ j(overflow, &string_add_runtime); | 5544 __ j(overflow, &call_runtime); |
5545 // Use the symbol table when adding two one character strings, as it | 5545 // Use the symbol table when adding two one character strings, as it |
5546 // helps later optimizations to return a symbol here. | 5546 // helps later optimizations to return a symbol here. |
5547 __ cmp(ebx, Immediate(Smi::FromInt(2))); | 5547 __ cmp(ebx, Immediate(Smi::FromInt(2))); |
5548 __ j(not_equal, &longer_than_two); | 5548 __ j(not_equal, &longer_than_two); |
5549 | 5549 |
5550 // Check that both strings are non-external ascii strings. | 5550 // Check that both strings are non-external ascii strings. |
5551 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, | 5551 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); |
5552 &string_add_runtime); | |
5553 | 5552 |
5554 // Get the two characters forming the new string. | 5553 // Get the two characters forming the new string. |
5555 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 5554 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
5556 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 5555 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
5557 | 5556 |
5558 // Try to lookup two character string in symbol table. If it is not found | 5557 // Try to lookup two character string in symbol table. If it is not found |
5559 // just allocate a new one. | 5558 // just allocate a new one. |
5560 Label make_two_character_string, make_two_character_string_no_reload; | 5559 Label make_two_character_string, make_two_character_string_no_reload; |
5561 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 5560 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
5562 masm, ebx, ecx, eax, edx, edi, | 5561 masm, ebx, ecx, eax, edx, edi, |
5563 &make_two_character_string_no_reload, &make_two_character_string); | 5562 &make_two_character_string_no_reload, &make_two_character_string); |
5564 __ IncrementCounter(counters->string_add_native(), 1); | 5563 __ IncrementCounter(counters->string_add_native(), 1); |
5565 __ ret(2 * kPointerSize); | 5564 __ ret(2 * kPointerSize); |
5566 | 5565 |
5567 // Allocate a two character string. | 5566 // Allocate a two character string. |
5568 __ bind(&make_two_character_string); | 5567 __ bind(&make_two_character_string); |
5569 // Reload the arguments. | 5568 // Reload the arguments. |
5570 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 5569 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
5571 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 5570 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
5572 // Get the two characters forming the new string. | 5571 // Get the two characters forming the new string. |
5573 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 5572 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
5574 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 5573 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
5575 __ bind(&make_two_character_string_no_reload); | 5574 __ bind(&make_two_character_string_no_reload); |
5576 __ IncrementCounter(counters->string_add_make_two_char(), 1); | 5575 __ IncrementCounter(counters->string_add_make_two_char(), 1); |
5577 __ AllocateAsciiString(eax, // Result. | 5576 __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); |
5578 2, // Length. | |
5579 edi, // Scratch 1. | |
5580 edx, // Scratch 2. | |
5581 &string_add_runtime); | |
5582 // Pack both characters in ebx. | 5577 // Pack both characters in ebx. |
5583 __ shl(ecx, kBitsPerByte); | 5578 __ shl(ecx, kBitsPerByte); |
5584 __ or_(ebx, ecx); | 5579 __ or_(ebx, ecx); |
5585 // Set the characters in the new string. | 5580 // Set the characters in the new string. |
5586 __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); | 5581 __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); |
5587 __ IncrementCounter(counters->string_add_native(), 1); | 5582 __ IncrementCounter(counters->string_add_native(), 1); |
5588 __ ret(2 * kPointerSize); | 5583 __ ret(2 * kPointerSize); |
5589 | 5584 |
5590 __ bind(&longer_than_two); | 5585 __ bind(&longer_than_two); |
5591 // Check if resulting string will be flat. | 5586 // Check if resulting string will be flat. |
5592 __ cmp(ebx, Immediate(Smi::FromInt(String::kMinNonFlatLength))); | 5587 __ cmp(ebx, Immediate(Smi::FromInt(String::kMinNonFlatLength))); |
5593 __ j(below, &string_add_flat_result); | 5588 __ j(below, &string_add_flat_result); |
5594 | 5589 |
5595 // If result is not supposed to be flat allocate a cons string object. If both | 5590 // If result is not supposed to be flat allocate a cons string object. If both |
5596 // strings are ascii the result is an ascii cons string. | 5591 // strings are ascii the result is an ascii cons string. |
5597 Label non_ascii, allocated, ascii_data; | 5592 Label non_ascii, allocated, ascii_data; |
5598 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); | 5593 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); |
5599 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); | 5594 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); |
5600 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 5595 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
5601 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | 5596 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); |
5602 __ and_(ecx, edi); | 5597 __ and_(ecx, edi); |
5603 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | 5598 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |
5604 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 5599 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
5605 __ test(ecx, Immediate(kStringEncodingMask)); | 5600 __ test(ecx, Immediate(kStringEncodingMask)); |
5606 __ j(zero, &non_ascii); | 5601 __ j(zero, &non_ascii, Label::kNear); |
5607 __ bind(&ascii_data); | 5602 __ bind(&ascii_data); |
5608 // Allocate an acsii cons string. | 5603 // Allocate an acsii cons string. |
5609 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); | 5604 __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); |
5610 __ bind(&allocated); | 5605 __ bind(&allocated); |
5611 // Fill the fields of the cons string. | 5606 // Fill the fields of the cons string. |
5612 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); | 5607 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); |
5613 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | 5608 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); |
5614 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | 5609 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), |
5615 Immediate(String::kEmptyHashField)); | 5610 Immediate(String::kEmptyHashField)); |
5616 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | 5611 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); |
5617 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | 5612 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); |
5618 __ mov(eax, ecx); | 5613 __ mov(eax, ecx); |
5619 __ IncrementCounter(counters->string_add_native(), 1); | 5614 __ IncrementCounter(counters->string_add_native(), 1); |
5620 __ ret(2 * kPointerSize); | 5615 __ ret(2 * kPointerSize); |
5621 __ bind(&non_ascii); | 5616 __ bind(&non_ascii); |
5622 // At least one of the strings is two-byte. Check whether it happens | 5617 // At least one of the strings is two-byte. Check whether it happens |
5623 // to contain only ascii characters. | 5618 // to contain only ascii characters. |
5624 // ecx: first instance type AND second instance type. | 5619 // ecx: first instance type AND second instance type. |
5625 // edi: second instance type. | 5620 // edi: second instance type. |
5626 __ test(ecx, Immediate(kAsciiDataHintMask)); | 5621 __ test(ecx, Immediate(kAsciiDataHintMask)); |
5627 __ j(not_zero, &ascii_data); | 5622 __ j(not_zero, &ascii_data); |
5628 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 5623 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
5629 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 5624 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
5630 __ xor_(edi, ecx); | 5625 __ xor_(edi, ecx); |
5631 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 5626 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |
5632 __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); | 5627 __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); |
5633 __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); | 5628 __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); |
5634 __ j(equal, &ascii_data); | 5629 __ j(equal, &ascii_data); |
5635 // Allocate a two byte cons string. | 5630 // Allocate a two byte cons string. |
5636 __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime); | 5631 __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); |
5637 __ jmp(&allocated); | 5632 __ jmp(&allocated); |
5638 | 5633 |
5639 // Handle creating a flat result. First check that both strings are not | 5634 // We cannot encounter sliced strings or cons strings here since: |
5640 // external strings. | 5635 STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); |
| 5636 // Handle creating a flat result from either external or sequential strings. |
| 5637 // Locate the first characters' locations. |
5641 // eax: first string | 5638 // eax: first string |
5642 // ebx: length of resulting flat string as a smi | 5639 // ebx: length of resulting flat string as a smi |
5643 // edx: second string | 5640 // edx: second string |
| 5641 Label first_prepared, second_prepared; |
| 5642 Label first_is_sequential, second_is_sequential; |
5644 __ bind(&string_add_flat_result); | 5643 __ bind(&string_add_flat_result); |
5645 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 5644 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
5646 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 5645 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
5647 __ and_(ecx, kStringRepresentationMask); | 5646 // ecx: instance type of first string |
5648 __ cmp(ecx, kExternalStringTag); | 5647 STATIC_ASSERT(kSeqStringTag == 0); |
5649 __ j(equal, &string_add_runtime); | 5648 __ test_b(ecx, kStringRepresentationMask); |
5650 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 5649 __ j(zero, &first_is_sequential, Label::kNear); |
5651 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 5650 // Rule out short external string and prepare it so that offset-wise, it |
5652 __ and_(ecx, kStringRepresentationMask); | 5651 // looks like a sequential string. |
5653 __ cmp(ecx, kExternalStringTag); | 5652 STATIC_ASSERT(kShortExternalStringTag != 0); |
5654 __ j(equal, &string_add_runtime); | 5653 __ test_b(ecx, kShortExternalStringMask); |
5655 // We cannot encounter sliced strings here since: | 5654 __ j(not_zero, &call_runtime); |
5656 STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength); | 5655 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); |
5657 // Now check if both strings are ascii strings. | 5656 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
5658 // eax: first string | 5657 __ jmp(&first_prepared, Label::kNear); |
5659 // ebx: length of resulting flat string as a smi | 5658 __ bind(&first_is_sequential); |
5660 // edx: second string | 5659 __ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
5661 Label non_ascii_string_add_flat_result; | 5660 __ bind(&first_prepared); |
5662 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | 5661 |
5663 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 5662 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
5664 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 5663 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); |
5665 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); | 5664 // Check whether both strings have same encoding. |
| 5665 // edi: instance type of second string |
| 5666 __ xor_(ecx, edi); |
| 5667 __ test_b(ecx, kStringEncodingMask); |
| 5668 __ j(not_zero, &call_runtime); |
| 5669 STATIC_ASSERT(kSeqStringTag == 0); |
| 5670 __ test_b(edi, kStringRepresentationMask); |
| 5671 __ j(zero, &second_is_sequential, Label::kNear); |
| 5672 // Rule out short external string and prepare it so that offset-wise, it |
| 5673 // looks like a sequential string. |
| 5674 STATIC_ASSERT(kShortExternalStringTag != 0); |
| 5675 __ test_b(edi, kShortExternalStringMask); |
| 5676 __ j(not_zero, &call_runtime); |
| 5677 __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); |
| 5678 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
| 5679 __ jmp(&second_prepared, Label::kNear); |
| 5680 __ bind(&second_is_sequential); |
| 5681 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5682 __ bind(&second_prepared); |
| 5683 |
| 5684 // Push the addresses of both strings' first characters onto the stack. |
| 5685 __ push(edx); |
| 5686 __ push(eax); |
| 5687 |
| 5688 Label non_ascii_string_add_flat_result, call_runtime_drop_two; |
| 5689 // edi: instance type of second string |
| 5690 // First string and second string have the same encoding. |
| 5691 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 5692 __ test_b(edi, kStringEncodingMask); |
5666 __ j(zero, &non_ascii_string_add_flat_result); | 5693 __ j(zero, &non_ascii_string_add_flat_result); |
5667 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
5668 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); | |
5669 __ j(zero, &string_add_runtime); | |
5670 | 5694 |
5671 // Both strings are ascii strings. As they are short they are both flat. | 5695 // Both strings are ascii strings. |
5672 // ebx: length of resulting flat string as a smi | 5696 // ebx: length of resulting flat string as a smi |
5673 __ SmiUntag(ebx); | 5697 __ SmiUntag(ebx); |
5674 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 5698 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); |
5675 // eax: result string | 5699 // eax: result string |
5676 __ mov(ecx, eax); | 5700 __ mov(ecx, eax); |
5677 // Locate first character of result. | 5701 // Locate first character of result. |
5678 __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 5702 __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
5679 // Load first argument and locate first character. | 5703 // Load first argument's length and first character location. Account for |
5680 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 5704 // values currently on the stack when fetching arguments from it. |
| 5705 __ mov(edx, Operand(esp, 4 * kPointerSize)); |
5681 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 5706 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
5682 __ SmiUntag(edi); | 5707 __ SmiUntag(edi); |
5683 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 5708 __ pop(edx); |
5684 // eax: result string | 5709 // eax: result string |
5685 // ecx: first character of result | 5710 // ecx: first character of result |
5686 // edx: first char of first argument | 5711 // edx: first char of first argument |
5687 // edi: length of first argument | 5712 // edi: length of first argument |
5688 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 5713 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
5689 // Load second argument and locate first character. | 5714 // Load second argument's length and first character location. Account for |
5690 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 5715 // values currently on the stack when fetching arguments from it. |
| 5716 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
5691 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 5717 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
5692 __ SmiUntag(edi); | 5718 __ SmiUntag(edi); |
5693 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 5719 __ pop(edx); |
5694 // eax: result string | 5720 // eax: result string |
5695 // ecx: next character of result | 5721 // ecx: next character of result |
5696 // edx: first char of second argument | 5722 // edx: first char of second argument |
5697 // edi: length of second argument | 5723 // edi: length of second argument |
5698 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 5724 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
5699 __ IncrementCounter(counters->string_add_native(), 1); | 5725 __ IncrementCounter(counters->string_add_native(), 1); |
5700 __ ret(2 * kPointerSize); | 5726 __ ret(2 * kPointerSize); |
5701 | 5727 |
5702 // Handle creating a flat two byte result. | 5728 // Handle creating a flat two byte result. |
5703 // eax: first string - known to be two byte | 5729 // eax: first string - known to be two byte |
5704 // ebx: length of resulting flat string as a smi | 5730 // ebx: length of resulting flat string as a smi |
5705 // edx: second string | 5731 // edx: second string |
5706 __ bind(&non_ascii_string_add_flat_result); | 5732 __ bind(&non_ascii_string_add_flat_result); |
5707 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 5733 // Both strings are two byte strings. |
5708 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); | |
5709 __ j(not_zero, &string_add_runtime); | |
5710 // Both strings are two byte strings. As they are short they are both | |
5711 // flat. | |
5712 __ SmiUntag(ebx); | 5734 __ SmiUntag(ebx); |
5713 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 5735 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); |
5714 // eax: result string | 5736 // eax: result string |
5715 __ mov(ecx, eax); | 5737 __ mov(ecx, eax); |
5716 // Locate first character of result. | 5738 // Locate first character of result. |
5717 __ add(ecx, | 5739 __ add(ecx, |
5718 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 5740 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
5719 // Load first argument and locate first character. | 5741 // Load second argument's length and first character location. Account for |
5720 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 5742 // values currently on the stack when fetching arguments from it. |
| 5743 __ mov(edx, Operand(esp, 4 * kPointerSize)); |
5721 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 5744 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
5722 __ SmiUntag(edi); | 5745 __ SmiUntag(edi); |
5723 __ add(edx, | 5746 __ pop(edx); |
5724 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
5725 // eax: result string | 5747 // eax: result string |
5726 // ecx: first character of result | 5748 // ecx: first character of result |
5727 // edx: first char of first argument | 5749 // edx: first char of first argument |
5728 // edi: length of first argument | 5750 // edi: length of first argument |
5729 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 5751 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
5730 // Load second argument and locate first character. | 5752 // Load second argument's length and first character location. Account for |
5731 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 5753 // values currently on the stack when fetching arguments from it. |
| 5754 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
5732 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 5755 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
5733 __ SmiUntag(edi); | 5756 __ SmiUntag(edi); |
5734 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 5757 __ pop(edx); |
5735 // eax: result string | 5758 // eax: result string |
5736 // ecx: next character of result | 5759 // ecx: next character of result |
5737 // edx: first char of second argument | 5760 // edx: first char of second argument |
5738 // edi: length of second argument | 5761 // edi: length of second argument |
5739 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 5762 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
5740 __ IncrementCounter(counters->string_add_native(), 1); | 5763 __ IncrementCounter(counters->string_add_native(), 1); |
5741 __ ret(2 * kPointerSize); | 5764 __ ret(2 * kPointerSize); |
5742 | 5765 |
| 5766 // Recover stack pointer before jumping to runtime. |
| 5767 __ bind(&call_runtime_drop_two); |
| 5768 __ Drop(2); |
5743 // Just jump to runtime to add the two strings. | 5769 // Just jump to runtime to add the two strings. |
5744 __ bind(&string_add_runtime); | 5770 __ bind(&call_runtime); |
5745 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 5771 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
5746 | 5772 |
5747 if (call_builtin.is_linked()) { | 5773 if (call_builtin.is_linked()) { |
5748 __ bind(&call_builtin); | 5774 __ bind(&call_builtin); |
5749 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 5775 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
5750 } | 5776 } |
5751 } | 5777 } |
5752 | 5778 |
5753 | 5779 |
5754 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | 5780 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, |
(...skipping 1555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7310 false); | 7336 false); |
7311 __ pop(edx); | 7337 __ pop(edx); |
7312 __ ret(0); | 7338 __ ret(0); |
7313 } | 7339 } |
7314 | 7340 |
7315 #undef __ | 7341 #undef __ |
7316 | 7342 |
7317 } } // namespace v8::internal | 7343 } } // namespace v8::internal |
7318 | 7344 |
7319 #endif // V8_TARGET_ARCH_IA32 | 7345 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |