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