OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 2675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2686 is_string.Bind(&left_side); | 2686 is_string.Bind(&left_side); |
2687 // left_side is a sequential ASCII string. | 2687 // left_side is a sequential ASCII string. |
2688 left_side = Result(left_reg); | 2688 left_side = Result(left_reg); |
2689 right_side = Result(right_val); | 2689 right_side = Result(right_val); |
2690 Result temp2 = allocator_->Allocate(); | 2690 Result temp2 = allocator_->Allocate(); |
2691 ASSERT(temp2.is_valid()); | 2691 ASSERT(temp2.is_valid()); |
2692 // Test string equality and comparison. | 2692 // Test string equality and comparison. |
2693 if (cc == equal) { | 2693 if (cc == equal) { |
2694 Label comparison_done; | 2694 Label comparison_done; |
2695 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2695 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2696 Immediate(Smi::FromInt(1))); | 2696 Immediate(1)); |
2697 __ j(not_equal, &comparison_done); | 2697 __ j(not_equal, &comparison_done); |
2698 uint8_t char_value = | 2698 uint8_t char_value = |
2699 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 2699 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
2700 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), | 2700 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), |
2701 char_value); | 2701 char_value); |
2702 __ bind(&comparison_done); | 2702 __ bind(&comparison_done); |
2703 } else { | 2703 } else { |
2704 __ mov(temp2.reg(), | 2704 __ mov(temp2.reg(), |
2705 FieldOperand(left_side.reg(), String::kLengthOffset)); | 2705 FieldOperand(left_side.reg(), String::kLengthOffset)); |
2706 __ SmiUntag(temp2.reg()); | |
2707 __ sub(Operand(temp2.reg()), Immediate(1)); | 2706 __ sub(Operand(temp2.reg()), Immediate(1)); |
2708 Label comparison; | 2707 Label comparison; |
2709 // If the length is 0 then the subtraction gave -1 which compares less | 2708 // If the length is 0 then the subtraction gave -1 which compares less |
2710 // than any character. | 2709 // than any character. |
2711 __ j(negative, &comparison); | 2710 __ j(negative, &comparison); |
2712 // Otherwise load the first character. | 2711 // Otherwise load the first character. |
2713 __ movzx_b(temp2.reg(), | 2712 __ movzx_b(temp2.reg(), |
2714 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); | 2713 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); |
2715 __ bind(&comparison); | 2714 __ bind(&comparison); |
2716 // Compare the first character of the string with the | 2715 // Compare the first character of the string with the |
2717 // constant 1-character string. | 2716 // constant 1-character string. |
2718 uint8_t char_value = | 2717 uint8_t char_value = |
2719 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 2718 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
2720 __ cmp(Operand(temp2.reg()), Immediate(char_value)); | 2719 __ cmp(Operand(temp2.reg()), Immediate(char_value)); |
2721 Label characters_were_different; | 2720 Label characters_were_different; |
2722 __ j(not_equal, &characters_were_different); | 2721 __ j(not_equal, &characters_were_different); |
2723 // If the first character is the same then the long string sorts after | 2722 // If the first character is the same then the long string sorts after |
2724 // the short one. | 2723 // the short one. |
2725 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2724 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2726 Immediate(Smi::FromInt(1))); | 2725 Immediate(1)); |
2727 __ bind(&characters_were_different); | 2726 __ bind(&characters_were_different); |
2728 } | 2727 } |
2729 temp2.Unuse(); | 2728 temp2.Unuse(); |
2730 left_side.Unuse(); | 2729 left_side.Unuse(); |
2731 right_side.Unuse(); | 2730 right_side.Unuse(); |
2732 dest->Split(cc); | 2731 dest->Split(cc); |
2733 } | 2732 } |
2734 } else { | 2733 } else { |
2735 // Neither side is a constant Smi, constant 1-char string or constant null. | 2734 // Neither side is a constant Smi, constant 1-char string or constant null. |
2736 // If either side is a non-smi constant, or known to be a heap number skip | 2735 // If either side is a non-smi constant, or known to be a heap number skip |
(...skipping 6076 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8813 __ j(not_zero, &false_result); | 8812 __ j(not_zero, &false_result); |
8814 | 8813 |
8815 // JavaScript object => true. | 8814 // JavaScript object => true. |
8816 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 8815 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
8817 __ j(above_equal, &true_result); | 8816 __ j(above_equal, &true_result); |
8818 | 8817 |
8819 // String value => false iff empty. | 8818 // String value => false iff empty. |
8820 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 8819 __ cmp(ecx, FIRST_NONSTRING_TYPE); |
8821 __ j(above_equal, ¬_string); | 8820 __ j(above_equal, ¬_string); |
8822 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); | 8821 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); |
8823 ASSERT(kSmiTag == 0); | |
8824 __ test(edx, Operand(edx)); | 8822 __ test(edx, Operand(edx)); |
8825 __ j(zero, &false_result); | 8823 __ j(zero, &false_result); |
8826 __ jmp(&true_result); | 8824 __ jmp(&true_result); |
8827 | 8825 |
8828 __ bind(¬_string); | 8826 __ bind(¬_string); |
8829 // HeapNumber => false iff +0, -0, or NaN. | 8827 // HeapNumber => false iff +0, -0, or NaN. |
8830 __ cmp(edx, Factory::heap_number_map()); | 8828 __ cmp(edx, Factory::heap_number_map()); |
8831 __ j(not_equal, &true_result); | 8829 __ j(not_equal, &true_result); |
8832 __ fldz(); | 8830 __ fldz(); |
8833 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 8831 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
(...skipping 1936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10770 // edx: Number of capture registers | 10768 // edx: Number of capture registers |
10771 // Check that the second argument is a string. | 10769 // Check that the second argument is a string. |
10772 __ mov(eax, Operand(esp, kSubjectOffset)); | 10770 __ mov(eax, Operand(esp, kSubjectOffset)); |
10773 __ test(eax, Immediate(kSmiTagMask)); | 10771 __ test(eax, Immediate(kSmiTagMask)); |
10774 __ j(zero, &runtime); | 10772 __ j(zero, &runtime); |
10775 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); | 10773 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |
10776 __ j(NegateCondition(is_string), &runtime); | 10774 __ j(NegateCondition(is_string), &runtime); |
10777 // Get the length of the string to ebx. | 10775 // Get the length of the string to ebx. |
10778 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 10776 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
10779 | 10777 |
10780 // ebx: Length of subject string as a smi | 10778 // ebx: Length of subject string |
10781 // ecx: RegExp data (FixedArray) | 10779 // ecx: RegExp data (FixedArray) |
10782 // edx: Number of capture registers | 10780 // edx: Number of capture registers |
10783 // Check that the third argument is a positive smi less than the subject | 10781 // Check that the third argument is a positive smi less than the subject |
10784 // string length. A negative value will be greater (unsigned comparison). | 10782 // string length. A negative value will be greater (unsigned comparison). |
10785 __ mov(eax, Operand(esp, kPreviousIndexOffset)); | 10783 __ mov(eax, Operand(esp, kPreviousIndexOffset)); |
10786 __ test(eax, Immediate(kSmiTagMask)); | 10784 __ SmiUntag(eax); |
10787 __ j(zero, &runtime); | |
10788 __ cmp(eax, Operand(ebx)); | 10785 __ cmp(eax, Operand(ebx)); |
10789 __ j(above_equal, &runtime); | 10786 __ j(above, &runtime); |
10790 | 10787 |
10791 // ecx: RegExp data (FixedArray) | 10788 // ecx: RegExp data (FixedArray) |
10792 // edx: Number of capture registers | 10789 // edx: Number of capture registers |
10793 // Check that the fourth object is a JSArray object. | 10790 // Check that the fourth object is a JSArray object. |
10794 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 10791 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |
10795 __ test(eax, Immediate(kSmiTagMask)); | 10792 __ test(eax, Immediate(kSmiTagMask)); |
10796 __ j(zero, &runtime); | 10793 __ j(zero, &runtime); |
10797 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); | 10794 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
10798 __ j(not_equal, &runtime); | 10795 __ j(not_equal, &runtime); |
10799 // Check that the JSArray is in fast case. | 10796 // Check that the JSArray is in fast case. |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10902 // Argument 5: static offsets vector buffer. | 10899 // Argument 5: static offsets vector buffer. |
10903 __ mov(Operand(esp, 4 * kPointerSize), | 10900 __ mov(Operand(esp, 4 * kPointerSize), |
10904 Immediate(ExternalReference::address_of_static_offsets_vector())); | 10901 Immediate(ExternalReference::address_of_static_offsets_vector())); |
10905 | 10902 |
10906 // Argument 4: End of string data | 10903 // Argument 4: End of string data |
10907 // Argument 3: Start of string data | 10904 // Argument 3: Start of string data |
10908 Label setup_two_byte, setup_rest; | 10905 Label setup_two_byte, setup_rest; |
10909 __ test(edi, Operand(edi)); | 10906 __ test(edi, Operand(edi)); |
10910 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); | 10907 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); |
10911 __ j(zero, &setup_two_byte); | 10908 __ j(zero, &setup_two_byte); |
10912 __ SmiUntag(edi); | |
10913 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); | 10909 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); |
10914 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | 10910 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
10915 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 10911 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |
10916 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | 10912 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
10917 __ jmp(&setup_rest); | 10913 __ jmp(&setup_rest); |
10918 | 10914 |
10919 __ bind(&setup_two_byte); | 10915 __ bind(&setup_two_byte); |
10920 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); // edi is smi (powered by 2). | 10916 __ lea(ecx, FieldOperand(eax, edi, times_2, SeqTwoByteString::kHeaderSize)); |
10921 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqTwoByteString::kHeaderSize)); | |
10922 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | 10917 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
10923 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | 10918 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); |
10924 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | 10919 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
10925 | 10920 |
10926 __ bind(&setup_rest); | 10921 __ bind(&setup_rest); |
10927 | 10922 |
10928 // Argument 2: Previous index. | 10923 // Argument 2: Previous index. |
10929 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 10924 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
10930 | 10925 |
10931 // Argument 1: Subject string. | 10926 // Argument 1: Subject string. |
(...skipping 1142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12074 // If the receiver is not a string trigger the non-string case. | 12069 // If the receiver is not a string trigger the non-string case. |
12075 __ test(result, Immediate(kIsNotStringMask)); | 12070 __ test(result, Immediate(kIsNotStringMask)); |
12076 __ j(not_zero, receiver_not_string); | 12071 __ j(not_zero, receiver_not_string); |
12077 | 12072 |
12078 // If the index is negative or non-smi trigger the non-positive-smi | 12073 // If the index is negative or non-smi trigger the non-positive-smi |
12079 // case. | 12074 // case. |
12080 ASSERT(kSmiTag == 0); | 12075 ASSERT(kSmiTag == 0); |
12081 __ test(index, Immediate(kSmiTagMask | kSmiSignMask)); | 12076 __ test(index, Immediate(kSmiTagMask | kSmiSignMask)); |
12082 __ j(not_zero, index_not_positive_smi); | 12077 __ j(not_zero, index_not_positive_smi); |
12083 | 12078 |
| 12079 // Put untagged index into scratch register. |
| 12080 __ mov(scratch, index); |
| 12081 __ SmiUntag(scratch); |
| 12082 |
12084 // Check for index out of range. | 12083 // Check for index out of range. |
12085 __ cmp(index, FieldOperand(object, String::kLengthOffset)); | 12084 __ cmp(scratch, FieldOperand(object, String::kLengthOffset)); |
12086 __ j(greater_equal, slow_case); | 12085 __ j(greater_equal, slow_case); |
12087 | 12086 |
12088 __ bind(&try_again_with_new_string); | 12087 __ bind(&try_again_with_new_string); |
12089 // ----------- S t a t e ------------- | 12088 // ----------- S t a t e ------------- |
12090 // -- object : string to access | 12089 // -- object : string to access |
12091 // -- result : instance type of the string | 12090 // -- result : instance type of the string |
12092 // -- scratch : positive smi index < length | 12091 // -- scratch : positive smi index < length |
12093 // ----------------------------------- | 12092 // ----------------------------------- |
12094 | 12093 |
12095 // We need special handling for non-flat strings. | 12094 // We need special handling for non-flat strings. |
12096 ASSERT(kSeqStringTag == 0); | 12095 ASSERT(kSeqStringTag == 0); |
12097 __ test(result, Immediate(kStringRepresentationMask)); | 12096 __ test(result, Immediate(kStringRepresentationMask)); |
12098 __ j(not_zero, ¬_a_flat_string); | 12097 __ j(not_zero, ¬_a_flat_string); |
12099 | 12098 |
12100 // Check for 1-byte or 2-byte string. | 12099 // Check for 1-byte or 2-byte string. |
12101 ASSERT(kAsciiStringTag != 0); | 12100 ASSERT(kAsciiStringTag != 0); |
12102 __ test(result, Immediate(kStringEncodingMask)); | 12101 __ test(result, Immediate(kStringEncodingMask)); |
12103 __ j(not_zero, &ascii_string); | 12102 __ j(not_zero, &ascii_string); |
12104 | 12103 |
12105 // 2-byte string. | 12104 // 2-byte string. |
12106 // Load the 2-byte character code into the temp register. | 12105 // Load the 2-byte character code into the temp register. |
12107 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // index is smi (powered by 2). | |
12108 __ movzx_w(result, FieldOperand(object, | 12106 __ movzx_w(result, FieldOperand(object, |
12109 index, times_1, | 12107 scratch, times_2, |
12110 SeqTwoByteString::kHeaderSize)); | 12108 SeqTwoByteString::kHeaderSize)); |
12111 __ jmp(&got_char_code); | 12109 __ jmp(&got_char_code); |
12112 | 12110 |
12113 // Handle non-flat strings. | 12111 // Handle non-flat strings. |
12114 __ bind(¬_a_flat_string); | 12112 __ bind(¬_a_flat_string); |
12115 __ and_(result, kStringRepresentationMask); | 12113 __ and_(result, kStringRepresentationMask); |
12116 __ cmp(result, kConsStringTag); | 12114 __ cmp(result, kConsStringTag); |
12117 __ j(not_equal, slow_case); | 12115 __ j(not_equal, slow_case); |
12118 | 12116 |
12119 // ConsString. | 12117 // ConsString. |
12120 // Check whether the right hand side is the empty string (i.e. if | 12118 // Check whether the right hand side is the empty string (i.e. if |
12121 // this is really a flat string in a cons string). If that is not | 12119 // this is really a flat string in a cons string). If that is not |
12122 // the case we would rather go to the runtime system now to flatten | 12120 // the case we would rather go to the runtime system now to flatten |
12123 // the string. | 12121 // the string. |
12124 __ mov(result, FieldOperand(object, ConsString::kSecondOffset)); | 12122 __ mov(result, FieldOperand(object, ConsString::kSecondOffset)); |
12125 __ cmp(Operand(result), Factory::empty_string()); | 12123 __ cmp(Operand(result), Factory::empty_string()); |
12126 __ j(not_equal, slow_case); | 12124 __ j(not_equal, slow_case); |
12127 // Get the first of the two strings and load its instance type. | 12125 // Get the first of the two strings and load its instance type. |
12128 __ mov(object, FieldOperand(object, ConsString::kFirstOffset)); | 12126 __ mov(object, FieldOperand(object, ConsString::kFirstOffset)); |
12129 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); | 12127 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); |
12130 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); | 12128 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
12131 __ jmp(&try_again_with_new_string); | 12129 __ jmp(&try_again_with_new_string); |
12132 | 12130 |
12133 // ASCII string. | 12131 // ASCII string. |
12134 __ bind(&ascii_string); | 12132 __ bind(&ascii_string); |
12135 // Put untagged index into scratch register. | |
12136 __ mov(scratch, index); | |
12137 __ SmiUntag(scratch); | |
12138 | |
12139 // Load the byte into the temp register. | 12133 // Load the byte into the temp register. |
12140 __ movzx_b(result, FieldOperand(object, | 12134 __ movzx_b(result, FieldOperand(object, |
12141 scratch, times_1, | 12135 scratch, times_1, |
12142 SeqAsciiString::kHeaderSize)); | 12136 SeqAsciiString::kHeaderSize)); |
12143 __ bind(&got_char_code); | 12137 __ bind(&got_char_code); |
12144 __ SmiTag(result); | 12138 __ SmiTag(result); |
12145 } | 12139 } |
12146 | 12140 |
12147 | 12141 |
12148 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, | 12142 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12219 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); | 12213 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); |
12220 __ j(above_equal, &string_add_runtime); | 12214 __ j(above_equal, &string_add_runtime); |
12221 } | 12215 } |
12222 | 12216 |
12223 // Both arguments are strings. | 12217 // Both arguments are strings. |
12224 // eax: first string | 12218 // eax: first string |
12225 // edx: second string | 12219 // edx: second string |
12226 // Check if either of the strings are empty. In that case return the other. | 12220 // Check if either of the strings are empty. In that case return the other. |
12227 Label second_not_zero_length, both_not_zero_length; | 12221 Label second_not_zero_length, both_not_zero_length; |
12228 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | 12222 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); |
12229 ASSERT(kSmiTag == 0); | |
12230 __ test(ecx, Operand(ecx)); | 12223 __ test(ecx, Operand(ecx)); |
12231 __ j(not_zero, &second_not_zero_length); | 12224 __ j(not_zero, &second_not_zero_length); |
12232 // Second string is empty, result is first string which is already in eax. | 12225 // Second string is empty, result is first string which is already in eax. |
12233 __ IncrementCounter(&Counters::string_add_native, 1); | 12226 __ IncrementCounter(&Counters::string_add_native, 1); |
12234 __ ret(2 * kPointerSize); | 12227 __ ret(2 * kPointerSize); |
12235 __ bind(&second_not_zero_length); | 12228 __ bind(&second_not_zero_length); |
12236 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 12229 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
12237 ASSERT(kSmiTag == 0); | |
12238 __ test(ebx, Operand(ebx)); | 12230 __ test(ebx, Operand(ebx)); |
12239 __ j(not_zero, &both_not_zero_length); | 12231 __ j(not_zero, &both_not_zero_length); |
12240 // First string is empty, result is second string which is in edx. | 12232 // First string is empty, result is second string which is in edx. |
12241 __ mov(eax, edx); | 12233 __ mov(eax, edx); |
12242 __ IncrementCounter(&Counters::string_add_native, 1); | 12234 __ IncrementCounter(&Counters::string_add_native, 1); |
12243 __ ret(2 * kPointerSize); | 12235 __ ret(2 * kPointerSize); |
12244 | 12236 |
12245 // Both strings are non-empty. | 12237 // Both strings are non-empty. |
12246 // eax: first string | 12238 // eax: first string |
12247 // ebx: length of first string as a smi | 12239 // ebx: length of first string |
12248 // ecx: length of second string as a smi | 12240 // ecx: length of second string |
12249 // edx: second string | 12241 // edx: second string |
12250 // Look at the length of the result of adding the two strings. | 12242 // Look at the length of the result of adding the two strings. |
12251 Label string_add_flat_result, longer_than_two; | 12243 Label string_add_flat_result, longer_than_two; |
12252 __ bind(&both_not_zero_length); | 12244 __ bind(&both_not_zero_length); |
12253 __ add(ebx, Operand(ecx)); | 12245 __ add(ebx, Operand(ecx)); |
12254 ASSERT(Smi::kMaxValue == String::kMaxLength); | |
12255 // Handle exceptionally long strings in the runtime system. | |
12256 __ j(overflow, &string_add_runtime); | |
12257 // Use the runtime system when adding two one character strings, as it | 12246 // Use the runtime system when adding two one character strings, as it |
12258 // contains optimizations for this specific case using the symbol table. | 12247 // contains optimizations for this specific case using the symbol table. |
12259 __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); | 12248 __ cmp(ebx, 2); |
12260 __ j(not_equal, &longer_than_two); | 12249 __ j(not_equal, &longer_than_two); |
12261 | 12250 |
12262 // Check that both strings are non-external ascii strings. | 12251 // Check that both strings are non-external ascii strings. |
12263 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, | 12252 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, |
12264 &string_add_runtime); | 12253 &string_add_runtime); |
12265 | 12254 |
12266 // Get the two characters forming the sub string. | 12255 // Get the two characters forming the sub string. |
12267 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 12256 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
12268 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 12257 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
12269 | 12258 |
12270 // Try to lookup two character string in symbol table. If it is not found | 12259 // Try to lookup two character string in symbol table. If it is not found |
12271 // just allocate a new one. | 12260 // just allocate a new one. |
12272 Label make_two_character_string, make_flat_ascii_string; | 12261 Label make_two_character_string, make_flat_ascii_string; |
12273 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 12262 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
12274 masm, ebx, ecx, eax, edx, edi, &make_two_character_string); | 12263 masm, ebx, ecx, eax, edx, edi, &make_two_character_string); |
12275 __ IncrementCounter(&Counters::string_add_native, 1); | 12264 __ IncrementCounter(&Counters::string_add_native, 1); |
12276 __ ret(2 * kPointerSize); | 12265 __ ret(2 * kPointerSize); |
12277 | 12266 |
12278 __ bind(&make_two_character_string); | 12267 __ bind(&make_two_character_string); |
12279 __ Set(ebx, Immediate(Smi::FromInt(2))); | 12268 __ Set(ebx, Immediate(2)); |
12280 __ jmp(&make_flat_ascii_string); | 12269 __ jmp(&make_flat_ascii_string); |
12281 | 12270 |
12282 __ bind(&longer_than_two); | 12271 __ bind(&longer_than_two); |
12283 // Check if resulting string will be flat. | 12272 // Check if resulting string will be flat. |
12284 __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); | 12273 __ cmp(ebx, String::kMinNonFlatLength); |
12285 __ j(below, &string_add_flat_result); | 12274 __ j(below, &string_add_flat_result); |
| 12275 // Handle exceptionally long strings in the runtime system. |
| 12276 ASSERT((String::kMaxLength & 0x80000000) == 0); |
| 12277 __ cmp(ebx, String::kMaxLength); |
| 12278 __ j(above, &string_add_runtime); |
12286 | 12279 |
12287 // If result is not supposed to be flat allocate a cons string object. If both | 12280 // If result is not supposed to be flat allocate a cons string object. If both |
12288 // strings are ascii the result is an ascii cons string. | 12281 // strings are ascii the result is an ascii cons string. |
12289 Label non_ascii, allocated; | 12282 Label non_ascii, allocated; |
12290 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); | 12283 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); |
12291 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); | 12284 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); |
12292 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 12285 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
12293 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | 12286 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); |
12294 __ and_(ecx, Operand(edi)); | 12287 __ and_(ecx, Operand(edi)); |
12295 ASSERT(kStringEncodingMask == kAsciiStringTag); | 12288 ASSERT(kStringEncodingMask == kAsciiStringTag); |
12296 __ test(ecx, Immediate(kAsciiStringTag)); | 12289 __ test(ecx, Immediate(kAsciiStringTag)); |
12297 __ j(zero, &non_ascii); | 12290 __ j(zero, &non_ascii); |
12298 // Allocate an acsii cons string. | 12291 // Allocate an acsii cons string. |
12299 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); | 12292 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); |
12300 __ bind(&allocated); | 12293 __ bind(&allocated); |
12301 // Fill the fields of the cons string. | 12294 // Fill the fields of the cons string. |
12302 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); | |
12303 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | 12295 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); |
12304 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | 12296 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), |
12305 Immediate(String::kEmptyHashField)); | 12297 Immediate(String::kEmptyHashField)); |
12306 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | 12298 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); |
12307 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | 12299 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); |
12308 __ mov(eax, ecx); | 12300 __ mov(eax, ecx); |
12309 __ IncrementCounter(&Counters::string_add_native, 1); | 12301 __ IncrementCounter(&Counters::string_add_native, 1); |
12310 __ ret(2 * kPointerSize); | 12302 __ ret(2 * kPointerSize); |
12311 __ bind(&non_ascii); | 12303 __ bind(&non_ascii); |
12312 // Allocate a two byte cons string. | 12304 // Allocate a two byte cons string. |
12313 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); | 12305 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); |
12314 __ jmp(&allocated); | 12306 __ jmp(&allocated); |
12315 | 12307 |
12316 // Handle creating a flat result. First check that both strings are not | 12308 // Handle creating a flat result. First check that both strings are not |
12317 // external strings. | 12309 // external strings. |
12318 // eax: first string | 12310 // eax: first string |
12319 // ebx: length of resulting flat string as a smi | 12311 // ebx: length of resulting flat string |
12320 // edx: second string | 12312 // edx: second string |
12321 __ bind(&string_add_flat_result); | 12313 __ bind(&string_add_flat_result); |
12322 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 12314 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
12323 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12315 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12324 __ and_(ecx, kStringRepresentationMask); | 12316 __ and_(ecx, kStringRepresentationMask); |
12325 __ cmp(ecx, kExternalStringTag); | 12317 __ cmp(ecx, kExternalStringTag); |
12326 __ j(equal, &string_add_runtime); | 12318 __ j(equal, &string_add_runtime); |
12327 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12319 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12328 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12320 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12329 __ and_(ecx, kStringRepresentationMask); | 12321 __ and_(ecx, kStringRepresentationMask); |
12330 __ cmp(ecx, kExternalStringTag); | 12322 __ cmp(ecx, kExternalStringTag); |
12331 __ j(equal, &string_add_runtime); | 12323 __ j(equal, &string_add_runtime); |
12332 // Now check if both strings are ascii strings. | 12324 // Now check if both strings are ascii strings. |
12333 // eax: first string | 12325 // eax: first string |
12334 // ebx: length of resulting flat string as a smi | 12326 // ebx: length of resulting flat string |
12335 // edx: second string | 12327 // edx: second string |
12336 Label non_ascii_string_add_flat_result; | 12328 Label non_ascii_string_add_flat_result; |
12337 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 12329 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
12338 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12330 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12339 ASSERT(kStringEncodingMask == kAsciiStringTag); | 12331 ASSERT(kStringEncodingMask == kAsciiStringTag); |
12340 __ test(ecx, Immediate(kAsciiStringTag)); | 12332 __ test(ecx, Immediate(kAsciiStringTag)); |
12341 __ j(zero, &non_ascii_string_add_flat_result); | 12333 __ j(zero, &non_ascii_string_add_flat_result); |
12342 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12334 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12343 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12335 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12344 __ test(ecx, Immediate(kAsciiStringTag)); | 12336 __ test(ecx, Immediate(kAsciiStringTag)); |
12345 __ j(zero, &string_add_runtime); | 12337 __ j(zero, &string_add_runtime); |
12346 | 12338 |
12347 __ bind(&make_flat_ascii_string); | 12339 __ bind(&make_flat_ascii_string); |
12348 // Both strings are ascii strings. As they are short they are both flat. | 12340 // Both strings are ascii strings. As they are short they are both flat. |
12349 // ebx: length of resulting flat string as a smi | 12341 // ebx: length of resulting flat string |
12350 __ SmiUntag(ebx); | |
12351 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 12342 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
12352 // eax: result string | 12343 // eax: result string |
12353 __ mov(ecx, eax); | 12344 __ mov(ecx, eax); |
12354 // Locate first character of result. | 12345 // Locate first character of result. |
12355 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12346 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12356 // Load first argument and locate first character. | 12347 // Load first argument and locate first character. |
12357 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 12348 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
12358 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12349 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
12359 __ SmiUntag(edi); | |
12360 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12350 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12361 // eax: result string | 12351 // eax: result string |
12362 // ecx: first character of result | 12352 // ecx: first character of result |
12363 // edx: first char of first argument | 12353 // edx: first char of first argument |
12364 // edi: length of first argument | 12354 // edi: length of first argument |
12365 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 12355 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
12366 // Load second argument and locate first character. | 12356 // Load second argument and locate first character. |
12367 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 12357 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
12368 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12358 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
12369 __ SmiUntag(edi); | |
12370 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12359 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12371 // eax: result string | 12360 // eax: result string |
12372 // ecx: next character of result | 12361 // ecx: next character of result |
12373 // edx: first char of second argument | 12362 // edx: first char of second argument |
12374 // edi: length of second argument | 12363 // edi: length of second argument |
12375 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 12364 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
12376 __ IncrementCounter(&Counters::string_add_native, 1); | 12365 __ IncrementCounter(&Counters::string_add_native, 1); |
12377 __ ret(2 * kPointerSize); | 12366 __ ret(2 * kPointerSize); |
12378 | 12367 |
12379 // Handle creating a flat two byte result. | 12368 // Handle creating a flat two byte result. |
12380 // eax: first string - known to be two byte | 12369 // eax: first string - known to be two byte |
12381 // ebx: length of resulting flat string as a smi | 12370 // ebx: length of resulting flat string |
12382 // edx: second string | 12371 // edx: second string |
12383 __ bind(&non_ascii_string_add_flat_result); | 12372 __ bind(&non_ascii_string_add_flat_result); |
12384 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12373 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12385 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12374 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12386 __ and_(ecx, kAsciiStringTag); | 12375 __ and_(ecx, kAsciiStringTag); |
12387 __ j(not_zero, &string_add_runtime); | 12376 __ j(not_zero, &string_add_runtime); |
12388 // Both strings are two byte strings. As they are short they are both | 12377 // Both strings are two byte strings. As they are short they are both |
12389 // flat. | 12378 // flat. |
12390 __ SmiUntag(ebx); | |
12391 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 12379 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
12392 // eax: result string | 12380 // eax: result string |
12393 __ mov(ecx, eax); | 12381 __ mov(ecx, eax); |
12394 // Locate first character of result. | 12382 // Locate first character of result. |
12395 __ add(Operand(ecx), | 12383 __ add(Operand(ecx), |
12396 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 12384 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
12397 // Load first argument and locate first character. | 12385 // Load first argument and locate first character. |
12398 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 12386 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
12399 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12387 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
12400 __ SmiUntag(edi); | |
12401 __ add(Operand(edx), | 12388 __ add(Operand(edx), |
12402 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 12389 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
12403 // eax: result string | 12390 // eax: result string |
12404 // ecx: first character of result | 12391 // ecx: first character of result |
12405 // edx: first char of first argument | 12392 // edx: first char of first argument |
12406 // edi: length of first argument | 12393 // edi: length of first argument |
12407 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 12394 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
12408 // Load second argument and locate first character. | 12395 // Load second argument and locate first character. |
12409 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 12396 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
12410 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12397 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
12411 __ SmiUntag(edi); | |
12412 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12398 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12413 // eax: result string | 12399 // eax: result string |
12414 // ecx: next character of result | 12400 // ecx: next character of result |
12415 // edx: first char of second argument | 12401 // edx: first char of second argument |
12416 // edi: length of second argument | 12402 // edi: length of second argument |
12417 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 12403 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
12418 __ IncrementCounter(&Counters::string_add_native, 1); | 12404 __ IncrementCounter(&Counters::string_add_native, 1); |
12419 __ ret(2 * kPointerSize); | 12405 __ ret(2 * kPointerSize); |
12420 | 12406 |
12421 // Just jump to runtime to add the two strings. | 12407 // Just jump to runtime to add the two strings. |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12586 FieldOperand(symbol_table, | 12572 FieldOperand(symbol_table, |
12587 scratch, | 12573 scratch, |
12588 times_pointer_size, | 12574 times_pointer_size, |
12589 SymbolTable::kElementsStartOffset)); | 12575 SymbolTable::kElementsStartOffset)); |
12590 | 12576 |
12591 // If entry is undefined no string with this hash can be found. | 12577 // If entry is undefined no string with this hash can be found. |
12592 __ cmp(candidate, Factory::undefined_value()); | 12578 __ cmp(candidate, Factory::undefined_value()); |
12593 __ j(equal, not_found); | 12579 __ j(equal, not_found); |
12594 | 12580 |
12595 // If length is not 2 the string is not a candidate. | 12581 // If length is not 2 the string is not a candidate. |
12596 __ cmp(FieldOperand(candidate, String::kLengthOffset), | 12582 __ cmp(FieldOperand(candidate, String::kLengthOffset), Immediate(2)); |
12597 Immediate(Smi::FromInt(2))); | |
12598 __ j(not_equal, &next_probe[i]); | 12583 __ j(not_equal, &next_probe[i]); |
12599 | 12584 |
12600 // As we are out of registers save the mask on the stack and use that | 12585 // As we are out of registers save the mask on the stack and use that |
12601 // register as a temporary. | 12586 // register as a temporary. |
12602 __ push(mask); | 12587 __ push(mask); |
12603 Register temp = mask; | 12588 Register temp = mask; |
12604 | 12589 |
12605 // Check that the candidate is a non-external ascii string. | 12590 // Check that the candidate is a non-external ascii string. |
12606 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); | 12591 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); |
12607 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | 12592 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12856 | 12841 |
12857 Register min_length = scratch1; | 12842 Register min_length = scratch1; |
12858 | 12843 |
12859 // If either length is zero, just compare lengths. | 12844 // If either length is zero, just compare lengths. |
12860 __ test(min_length, Operand(min_length)); | 12845 __ test(min_length, Operand(min_length)); |
12861 __ j(zero, &compare_lengths); | 12846 __ j(zero, &compare_lengths); |
12862 | 12847 |
12863 // Change index to run from -min_length to -1 by adding min_length | 12848 // Change index to run from -min_length to -1 by adding min_length |
12864 // to string start. This means that loop ends when index reaches zero, | 12849 // to string start. This means that loop ends when index reaches zero, |
12865 // which doesn't need an additional compare. | 12850 // which doesn't need an additional compare. |
12866 __ SmiUntag(min_length); | |
12867 __ lea(left, | 12851 __ lea(left, |
12868 FieldOperand(left, | 12852 FieldOperand(left, |
12869 min_length, times_1, | 12853 min_length, times_1, |
12870 SeqAsciiString::kHeaderSize)); | 12854 SeqAsciiString::kHeaderSize)); |
12871 __ lea(right, | 12855 __ lea(right, |
12872 FieldOperand(right, | 12856 FieldOperand(right, |
12873 min_length, times_1, | 12857 min_length, times_1, |
12874 SeqAsciiString::kHeaderSize)); | 12858 SeqAsciiString::kHeaderSize)); |
12875 __ neg(min_length); | 12859 __ neg(min_length); |
12876 | 12860 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12943 | 12927 |
12944 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12928 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
12945 // tagged as a small integer. | 12929 // tagged as a small integer. |
12946 __ bind(&runtime); | 12930 __ bind(&runtime); |
12947 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12931 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
12948 } | 12932 } |
12949 | 12933 |
12950 #undef __ | 12934 #undef __ |
12951 | 12935 |
12952 } } // namespace v8::internal | 12936 } } // namespace v8::internal |
OLD | NEW |