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 2676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2687 is_string.Bind(&left_side); | 2687 is_string.Bind(&left_side); |
2688 // left_side is a sequential ASCII string. | 2688 // left_side is a sequential ASCII string. |
2689 left_side = Result(left_reg); | 2689 left_side = Result(left_reg); |
2690 right_side = Result(right_val); | 2690 right_side = Result(right_val); |
2691 Result temp2 = allocator_->Allocate(); | 2691 Result temp2 = allocator_->Allocate(); |
2692 ASSERT(temp2.is_valid()); | 2692 ASSERT(temp2.is_valid()); |
2693 // Test string equality and comparison. | 2693 // Test string equality and comparison. |
2694 if (cc == equal) { | 2694 if (cc == equal) { |
2695 Label comparison_done; | 2695 Label comparison_done; |
2696 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2696 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2697 Immediate(1)); | 2697 Immediate(Smi::FromInt(1))); |
2698 __ j(not_equal, &comparison_done); | 2698 __ j(not_equal, &comparison_done); |
2699 uint8_t char_value = | 2699 uint8_t char_value = |
2700 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 2700 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
2701 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), | 2701 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), |
2702 char_value); | 2702 char_value); |
2703 __ bind(&comparison_done); | 2703 __ bind(&comparison_done); |
2704 } else { | 2704 } else { |
2705 __ mov(temp2.reg(), | 2705 __ mov(temp2.reg(), |
2706 FieldOperand(left_side.reg(), String::kLengthOffset)); | 2706 FieldOperand(left_side.reg(), String::kLengthOffset)); |
| 2707 __ SmiUntag(temp2.reg()); |
2707 __ sub(Operand(temp2.reg()), Immediate(1)); | 2708 __ sub(Operand(temp2.reg()), Immediate(1)); |
2708 Label comparison; | 2709 Label comparison; |
2709 // If the length is 0 then the subtraction gave -1 which compares less | 2710 // If the length is 0 then the subtraction gave -1 which compares less |
2710 // than any character. | 2711 // than any character. |
2711 __ j(negative, &comparison); | 2712 __ j(negative, &comparison); |
2712 // Otherwise load the first character. | 2713 // Otherwise load the first character. |
2713 __ movzx_b(temp2.reg(), | 2714 __ movzx_b(temp2.reg(), |
2714 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); | 2715 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); |
2715 __ bind(&comparison); | 2716 __ bind(&comparison); |
2716 // Compare the first character of the string with the | 2717 // Compare the first character of the string with the |
2717 // constant 1-character string. | 2718 // constant 1-character string. |
2718 uint8_t char_value = | 2719 uint8_t char_value = |
2719 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 2720 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
2720 __ cmp(Operand(temp2.reg()), Immediate(char_value)); | 2721 __ cmp(Operand(temp2.reg()), Immediate(char_value)); |
2721 Label characters_were_different; | 2722 Label characters_were_different; |
2722 __ j(not_equal, &characters_were_different); | 2723 __ j(not_equal, &characters_were_different); |
2723 // If the first character is the same then the long string sorts after | 2724 // If the first character is the same then the long string sorts after |
2724 // the short one. | 2725 // the short one. |
2725 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2726 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2726 Immediate(1)); | 2727 Immediate(Smi::FromInt(1))); |
2727 __ bind(&characters_were_different); | 2728 __ bind(&characters_were_different); |
2728 } | 2729 } |
2729 temp2.Unuse(); | 2730 temp2.Unuse(); |
2730 left_side.Unuse(); | 2731 left_side.Unuse(); |
2731 right_side.Unuse(); | 2732 right_side.Unuse(); |
2732 dest->Split(cc); | 2733 dest->Split(cc); |
2733 } | 2734 } |
2734 } else { | 2735 } else { |
2735 // Neither side is a constant Smi, constant 1-char string or constant null. | 2736 // 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 | 2737 // If either side is a non-smi constant, or known to be a heap number skip |
(...skipping 6196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8933 __ j(not_zero, &false_result); | 8934 __ j(not_zero, &false_result); |
8934 | 8935 |
8935 // JavaScript object => true. | 8936 // JavaScript object => true. |
8936 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 8937 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
8937 __ j(above_equal, &true_result); | 8938 __ j(above_equal, &true_result); |
8938 | 8939 |
8939 // String value => false iff empty. | 8940 // String value => false iff empty. |
8940 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 8941 __ cmp(ecx, FIRST_NONSTRING_TYPE); |
8941 __ j(above_equal, ¬_string); | 8942 __ j(above_equal, ¬_string); |
8942 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); | 8943 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); |
| 8944 ASSERT(kSmiTag == 0); |
8943 __ test(edx, Operand(edx)); | 8945 __ test(edx, Operand(edx)); |
8944 __ j(zero, &false_result); | 8946 __ j(zero, &false_result); |
8945 __ jmp(&true_result); | 8947 __ jmp(&true_result); |
8946 | 8948 |
8947 __ bind(¬_string); | 8949 __ bind(¬_string); |
8948 // HeapNumber => false iff +0, -0, or NaN. | 8950 // HeapNumber => false iff +0, -0, or NaN. |
8949 __ cmp(edx, Factory::heap_number_map()); | 8951 __ cmp(edx, Factory::heap_number_map()); |
8950 __ j(not_equal, &true_result); | 8952 __ j(not_equal, &true_result); |
8951 __ fldz(); | 8953 __ fldz(); |
8952 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 8954 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
(...skipping 1936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10889 // edx: Number of capture registers | 10891 // edx: Number of capture registers |
10890 // Check that the second argument is a string. | 10892 // Check that the second argument is a string. |
10891 __ mov(eax, Operand(esp, kSubjectOffset)); | 10893 __ mov(eax, Operand(esp, kSubjectOffset)); |
10892 __ test(eax, Immediate(kSmiTagMask)); | 10894 __ test(eax, Immediate(kSmiTagMask)); |
10893 __ j(zero, &runtime); | 10895 __ j(zero, &runtime); |
10894 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); | 10896 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |
10895 __ j(NegateCondition(is_string), &runtime); | 10897 __ j(NegateCondition(is_string), &runtime); |
10896 // Get the length of the string to ebx. | 10898 // Get the length of the string to ebx. |
10897 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 10899 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
10898 | 10900 |
10899 // ebx: Length of subject string | 10901 // ebx: Length of subject string as a smi |
10900 // ecx: RegExp data (FixedArray) | 10902 // ecx: RegExp data (FixedArray) |
10901 // edx: Number of capture registers | 10903 // edx: Number of capture registers |
10902 // Check that the third argument is a positive smi less than the subject | 10904 // Check that the third argument is a positive smi less than the subject |
10903 // string length. A negative value will be greater (unsigned comparison). | 10905 // string length. A negative value will be greater (unsigned comparison). |
10904 __ mov(eax, Operand(esp, kPreviousIndexOffset)); | 10906 __ mov(eax, Operand(esp, kPreviousIndexOffset)); |
10905 __ SmiUntag(eax); | 10907 __ test(eax, Immediate(kSmiTagMask)); |
| 10908 __ j(zero, &runtime); |
10906 __ cmp(eax, Operand(ebx)); | 10909 __ cmp(eax, Operand(ebx)); |
10907 __ j(above, &runtime); | 10910 __ j(above_equal, &runtime); |
10908 | 10911 |
10909 // ecx: RegExp data (FixedArray) | 10912 // ecx: RegExp data (FixedArray) |
10910 // edx: Number of capture registers | 10913 // edx: Number of capture registers |
10911 // Check that the fourth object is a JSArray object. | 10914 // Check that the fourth object is a JSArray object. |
10912 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 10915 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |
10913 __ test(eax, Immediate(kSmiTagMask)); | 10916 __ test(eax, Immediate(kSmiTagMask)); |
10914 __ j(zero, &runtime); | 10917 __ j(zero, &runtime); |
10915 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); | 10918 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
10916 __ j(not_equal, &runtime); | 10919 __ j(not_equal, &runtime); |
10917 // Check that the JSArray is in fast case. | 10920 // Check that the JSArray is in fast case. |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11020 // Argument 5: static offsets vector buffer. | 11023 // Argument 5: static offsets vector buffer. |
11021 __ mov(Operand(esp, 4 * kPointerSize), | 11024 __ mov(Operand(esp, 4 * kPointerSize), |
11022 Immediate(ExternalReference::address_of_static_offsets_vector())); | 11025 Immediate(ExternalReference::address_of_static_offsets_vector())); |
11023 | 11026 |
11024 // Argument 4: End of string data | 11027 // Argument 4: End of string data |
11025 // Argument 3: Start of string data | 11028 // Argument 3: Start of string data |
11026 Label setup_two_byte, setup_rest; | 11029 Label setup_two_byte, setup_rest; |
11027 __ test(edi, Operand(edi)); | 11030 __ test(edi, Operand(edi)); |
11028 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); | 11031 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); |
11029 __ j(zero, &setup_two_byte); | 11032 __ j(zero, &setup_two_byte); |
| 11033 __ SmiUntag(edi); |
11030 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); | 11034 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); |
11031 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | 11035 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
11032 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 11036 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |
11033 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | 11037 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
11034 __ jmp(&setup_rest); | 11038 __ jmp(&setup_rest); |
11035 | 11039 |
11036 __ bind(&setup_two_byte); | 11040 __ bind(&setup_two_byte); |
11037 __ lea(ecx, FieldOperand(eax, edi, times_2, SeqTwoByteString::kHeaderSize)); | 11041 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); // edi is smi (powered by 2). |
| 11042 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqTwoByteString::kHeaderSize)); |
11038 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | 11043 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
11039 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | 11044 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); |
11040 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | 11045 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
11041 | 11046 |
11042 __ bind(&setup_rest); | 11047 __ bind(&setup_rest); |
11043 | 11048 |
11044 // Argument 2: Previous index. | 11049 // Argument 2: Previous index. |
11045 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 11050 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
11046 | 11051 |
11047 // Argument 1: Subject string. | 11052 // Argument 1: Subject string. |
(...skipping 1142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12190 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); | 12195 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
12191 // If the receiver is not a string trigger the non-string case. | 12196 // If the receiver is not a string trigger the non-string case. |
12192 __ test(result, Immediate(kIsNotStringMask)); | 12197 __ test(result, Immediate(kIsNotStringMask)); |
12193 __ j(not_zero, receiver_not_string); | 12198 __ j(not_zero, receiver_not_string); |
12194 | 12199 |
12195 // If the index is non-smi trigger the non-smi case. | 12200 // If the index is non-smi trigger the non-smi case. |
12196 ASSERT(kSmiTag == 0); | 12201 ASSERT(kSmiTag == 0); |
12197 __ test(index, Immediate(kSmiTagMask)); | 12202 __ test(index, Immediate(kSmiTagMask)); |
12198 __ j(not_zero, index_not_smi); | 12203 __ j(not_zero, index_not_smi); |
12199 | 12204 |
12200 // Put untagged index into scratch register. | |
12201 __ mov(scratch, index); | |
12202 __ SmiUntag(scratch); | |
12203 | |
12204 // Check for index out of range. | 12205 // Check for index out of range. |
12205 __ cmp(scratch, FieldOperand(object, String::kLengthOffset)); | 12206 __ cmp(index, FieldOperand(object, String::kLengthOffset)); |
12206 __ j(above_equal, index_out_of_range); | 12207 __ j(above_equal, index_out_of_range); |
12207 | 12208 |
12208 __ bind(&try_again_with_new_string); | 12209 __ bind(&try_again_with_new_string); |
12209 // ----------- S t a t e ------------- | 12210 // ----------- S t a t e ------------- |
12210 // -- object : string to access | 12211 // -- object : string to access |
12211 // -- result : instance type of the string | 12212 // -- result : instance type of the string |
12212 // -- scratch : non-negative index < length | 12213 // -- scratch : non-negative index < length |
12213 // ----------------------------------- | 12214 // ----------------------------------- |
12214 | 12215 |
12215 // We need special handling for non-flat strings. | 12216 // We need special handling for non-flat strings. |
12216 ASSERT(kSeqStringTag == 0); | 12217 ASSERT(kSeqStringTag == 0); |
12217 __ test(result, Immediate(kStringRepresentationMask)); | 12218 __ test(result, Immediate(kStringRepresentationMask)); |
12218 __ j(not_zero, ¬_a_flat_string); | 12219 __ j(not_zero, ¬_a_flat_string); |
12219 | 12220 |
12220 // Check for 1-byte or 2-byte string. | 12221 // Check for 1-byte or 2-byte string. |
12221 ASSERT(kAsciiStringTag != 0); | 12222 ASSERT(kAsciiStringTag != 0); |
12222 __ test(result, Immediate(kStringEncodingMask)); | 12223 __ test(result, Immediate(kStringEncodingMask)); |
12223 __ j(not_zero, &ascii_string); | 12224 __ j(not_zero, &ascii_string); |
12224 | 12225 |
12225 // 2-byte string. | 12226 // 2-byte string. |
12226 // Load the 2-byte character code into the result register. | 12227 // Load the 2-byte character code into the result register. |
| 12228 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); // index is smi (powered by 2). |
12227 __ movzx_w(result, FieldOperand(object, | 12229 __ movzx_w(result, FieldOperand(object, |
12228 scratch, times_2, | 12230 index, times_1, |
12229 SeqTwoByteString::kHeaderSize)); | 12231 SeqTwoByteString::kHeaderSize)); |
12230 __ jmp(&got_char_code); | 12232 __ jmp(&got_char_code); |
12231 | 12233 |
12232 // Handle non-flat strings. | 12234 // Handle non-flat strings. |
12233 __ bind(¬_a_flat_string); | 12235 __ bind(¬_a_flat_string); |
12234 __ and_(result, kStringRepresentationMask); | 12236 __ and_(result, kStringRepresentationMask); |
12235 __ cmp(result, kConsStringTag); | 12237 __ cmp(result, kConsStringTag); |
12236 __ j(not_equal, slow_case); | 12238 __ j(not_equal, slow_case); |
12237 | 12239 |
12238 // ConsString. | 12240 // ConsString. |
12239 // Check whether the right hand side is the empty string (i.e. if | 12241 // Check whether the right hand side is the empty string (i.e. if |
12240 // this is really a flat string in a cons string). If that is not | 12242 // this is really a flat string in a cons string). If that is not |
12241 // the case we would rather go to the runtime system now to flatten | 12243 // the case we would rather go to the runtime system now to flatten |
12242 // the string. | 12244 // the string. |
12243 __ mov(result, FieldOperand(object, ConsString::kSecondOffset)); | 12245 __ mov(result, FieldOperand(object, ConsString::kSecondOffset)); |
12244 __ cmp(Operand(result), Factory::empty_string()); | 12246 __ cmp(Operand(result), Factory::empty_string()); |
12245 __ j(not_equal, slow_case); | 12247 __ j(not_equal, slow_case); |
12246 // Get the first of the two strings and load its instance type. | 12248 // Get the first of the two strings and load its instance type. |
12247 __ mov(object, FieldOperand(object, ConsString::kFirstOffset)); | 12249 __ mov(object, FieldOperand(object, ConsString::kFirstOffset)); |
12248 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); | 12250 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); |
12249 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); | 12251 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
12250 __ jmp(&try_again_with_new_string); | 12252 __ jmp(&try_again_with_new_string); |
12251 | 12253 |
12252 // ASCII string. | 12254 // ASCII string. |
12253 __ bind(&ascii_string); | 12255 __ bind(&ascii_string); |
| 12256 // Put untagged index into scratch register. |
| 12257 __ mov(scratch, index); |
| 12258 __ SmiUntag(scratch); |
| 12259 |
12254 // Load the byte into the result register. | 12260 // Load the byte into the result register. |
12255 __ movzx_b(result, FieldOperand(object, | 12261 __ movzx_b(result, FieldOperand(object, |
12256 scratch, times_1, | 12262 scratch, times_1, |
12257 SeqAsciiString::kHeaderSize)); | 12263 SeqAsciiString::kHeaderSize)); |
12258 __ bind(&got_char_code); | 12264 __ bind(&got_char_code); |
12259 __ SmiTag(result); | 12265 __ SmiTag(result); |
12260 } | 12266 } |
12261 | 12267 |
12262 | 12268 |
12263 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, | 12269 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12334 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); | 12340 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); |
12335 __ j(above_equal, &string_add_runtime); | 12341 __ j(above_equal, &string_add_runtime); |
12336 } | 12342 } |
12337 | 12343 |
12338 // Both arguments are strings. | 12344 // Both arguments are strings. |
12339 // eax: first string | 12345 // eax: first string |
12340 // edx: second string | 12346 // edx: second string |
12341 // Check if either of the strings are empty. In that case return the other. | 12347 // Check if either of the strings are empty. In that case return the other. |
12342 Label second_not_zero_length, both_not_zero_length; | 12348 Label second_not_zero_length, both_not_zero_length; |
12343 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | 12349 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); |
| 12350 ASSERT(kSmiTag == 0); |
12344 __ test(ecx, Operand(ecx)); | 12351 __ test(ecx, Operand(ecx)); |
12345 __ j(not_zero, &second_not_zero_length); | 12352 __ j(not_zero, &second_not_zero_length); |
12346 // Second string is empty, result is first string which is already in eax. | 12353 // Second string is empty, result is first string which is already in eax. |
12347 __ IncrementCounter(&Counters::string_add_native, 1); | 12354 __ IncrementCounter(&Counters::string_add_native, 1); |
12348 __ ret(2 * kPointerSize); | 12355 __ ret(2 * kPointerSize); |
12349 __ bind(&second_not_zero_length); | 12356 __ bind(&second_not_zero_length); |
12350 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 12357 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
| 12358 ASSERT(kSmiTag == 0); |
12351 __ test(ebx, Operand(ebx)); | 12359 __ test(ebx, Operand(ebx)); |
12352 __ j(not_zero, &both_not_zero_length); | 12360 __ j(not_zero, &both_not_zero_length); |
12353 // First string is empty, result is second string which is in edx. | 12361 // First string is empty, result is second string which is in edx. |
12354 __ mov(eax, edx); | 12362 __ mov(eax, edx); |
12355 __ IncrementCounter(&Counters::string_add_native, 1); | 12363 __ IncrementCounter(&Counters::string_add_native, 1); |
12356 __ ret(2 * kPointerSize); | 12364 __ ret(2 * kPointerSize); |
12357 | 12365 |
12358 // Both strings are non-empty. | 12366 // Both strings are non-empty. |
12359 // eax: first string | 12367 // eax: first string |
12360 // ebx: length of first string | 12368 // ebx: length of first string as a smi |
12361 // ecx: length of second string | 12369 // ecx: length of second string as a smi |
12362 // edx: second string | 12370 // edx: second string |
12363 // Look at the length of the result of adding the two strings. | 12371 // Look at the length of the result of adding the two strings. |
12364 Label string_add_flat_result, longer_than_two; | 12372 Label string_add_flat_result, longer_than_two; |
12365 __ bind(&both_not_zero_length); | 12373 __ bind(&both_not_zero_length); |
12366 __ add(ebx, Operand(ecx)); | 12374 __ add(ebx, Operand(ecx)); |
| 12375 ASSERT(Smi::kMaxValue == String::kMaxLength); |
| 12376 // Handle exceptionally long strings in the runtime system. |
| 12377 __ j(overflow, &string_add_runtime); |
12367 // Use the runtime system when adding two one character strings, as it | 12378 // Use the runtime system when adding two one character strings, as it |
12368 // contains optimizations for this specific case using the symbol table. | 12379 // contains optimizations for this specific case using the symbol table. |
12369 __ cmp(ebx, 2); | 12380 __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); |
12370 __ j(not_equal, &longer_than_two); | 12381 __ j(not_equal, &longer_than_two); |
12371 | 12382 |
12372 // Check that both strings are non-external ascii strings. | 12383 // Check that both strings are non-external ascii strings. |
12373 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, | 12384 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, |
12374 &string_add_runtime); | 12385 &string_add_runtime); |
12375 | 12386 |
12376 // Get the two characters forming the sub string. | 12387 // Get the two characters forming the sub string. |
12377 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 12388 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
12378 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 12389 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
12379 | 12390 |
12380 // Try to lookup two character string in symbol table. If it is not found | 12391 // Try to lookup two character string in symbol table. If it is not found |
12381 // just allocate a new one. | 12392 // just allocate a new one. |
12382 Label make_two_character_string, make_flat_ascii_string; | 12393 Label make_two_character_string, make_flat_ascii_string; |
12383 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 12394 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
12384 masm, ebx, ecx, eax, edx, edi, &make_two_character_string); | 12395 masm, ebx, ecx, eax, edx, edi, &make_two_character_string); |
12385 __ IncrementCounter(&Counters::string_add_native, 1); | 12396 __ IncrementCounter(&Counters::string_add_native, 1); |
12386 __ ret(2 * kPointerSize); | 12397 __ ret(2 * kPointerSize); |
12387 | 12398 |
12388 __ bind(&make_two_character_string); | 12399 __ bind(&make_two_character_string); |
12389 __ Set(ebx, Immediate(2)); | 12400 __ Set(ebx, Immediate(Smi::FromInt(2))); |
12390 __ jmp(&make_flat_ascii_string); | 12401 __ jmp(&make_flat_ascii_string); |
12391 | 12402 |
12392 __ bind(&longer_than_two); | 12403 __ bind(&longer_than_two); |
12393 // Check if resulting string will be flat. | 12404 // Check if resulting string will be flat. |
12394 __ cmp(ebx, String::kMinNonFlatLength); | 12405 __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); |
12395 __ j(below, &string_add_flat_result); | 12406 __ j(below, &string_add_flat_result); |
12396 // Handle exceptionally long strings in the runtime system. | |
12397 ASSERT((String::kMaxLength & 0x80000000) == 0); | |
12398 __ cmp(ebx, String::kMaxLength); | |
12399 __ j(above, &string_add_runtime); | |
12400 | 12407 |
12401 // If result is not supposed to be flat allocate a cons string object. If both | 12408 // If result is not supposed to be flat allocate a cons string object. If both |
12402 // strings are ascii the result is an ascii cons string. | 12409 // strings are ascii the result is an ascii cons string. |
12403 Label non_ascii, allocated; | 12410 Label non_ascii, allocated; |
12404 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); | 12411 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); |
12405 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); | 12412 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); |
12406 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 12413 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
12407 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | 12414 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); |
12408 __ and_(ecx, Operand(edi)); | 12415 __ and_(ecx, Operand(edi)); |
12409 ASSERT(kStringEncodingMask == kAsciiStringTag); | 12416 ASSERT(kStringEncodingMask == kAsciiStringTag); |
12410 __ test(ecx, Immediate(kAsciiStringTag)); | 12417 __ test(ecx, Immediate(kAsciiStringTag)); |
12411 __ j(zero, &non_ascii); | 12418 __ j(zero, &non_ascii); |
12412 // Allocate an acsii cons string. | 12419 // Allocate an acsii cons string. |
12413 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); | 12420 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); |
12414 __ bind(&allocated); | 12421 __ bind(&allocated); |
12415 // Fill the fields of the cons string. | 12422 // Fill the fields of the cons string. |
| 12423 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); |
12416 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | 12424 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); |
12417 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | 12425 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), |
12418 Immediate(String::kEmptyHashField)); | 12426 Immediate(String::kEmptyHashField)); |
12419 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | 12427 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); |
12420 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | 12428 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); |
12421 __ mov(eax, ecx); | 12429 __ mov(eax, ecx); |
12422 __ IncrementCounter(&Counters::string_add_native, 1); | 12430 __ IncrementCounter(&Counters::string_add_native, 1); |
12423 __ ret(2 * kPointerSize); | 12431 __ ret(2 * kPointerSize); |
12424 __ bind(&non_ascii); | 12432 __ bind(&non_ascii); |
12425 // Allocate a two byte cons string. | 12433 // Allocate a two byte cons string. |
12426 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); | 12434 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); |
12427 __ jmp(&allocated); | 12435 __ jmp(&allocated); |
12428 | 12436 |
12429 // Handle creating a flat result. First check that both strings are not | 12437 // Handle creating a flat result. First check that both strings are not |
12430 // external strings. | 12438 // external strings. |
12431 // eax: first string | 12439 // eax: first string |
12432 // ebx: length of resulting flat string | 12440 // ebx: length of resulting flat string as a smi |
12433 // edx: second string | 12441 // edx: second string |
12434 __ bind(&string_add_flat_result); | 12442 __ bind(&string_add_flat_result); |
12435 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 12443 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
12436 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12444 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12437 __ and_(ecx, kStringRepresentationMask); | 12445 __ and_(ecx, kStringRepresentationMask); |
12438 __ cmp(ecx, kExternalStringTag); | 12446 __ cmp(ecx, kExternalStringTag); |
12439 __ j(equal, &string_add_runtime); | 12447 __ j(equal, &string_add_runtime); |
12440 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12448 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12441 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12449 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12442 __ and_(ecx, kStringRepresentationMask); | 12450 __ and_(ecx, kStringRepresentationMask); |
12443 __ cmp(ecx, kExternalStringTag); | 12451 __ cmp(ecx, kExternalStringTag); |
12444 __ j(equal, &string_add_runtime); | 12452 __ j(equal, &string_add_runtime); |
12445 // Now check if both strings are ascii strings. | 12453 // Now check if both strings are ascii strings. |
12446 // eax: first string | 12454 // eax: first string |
12447 // ebx: length of resulting flat string | 12455 // ebx: length of resulting flat string as a smi |
12448 // edx: second string | 12456 // edx: second string |
12449 Label non_ascii_string_add_flat_result; | 12457 Label non_ascii_string_add_flat_result; |
12450 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 12458 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
12451 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12459 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12452 ASSERT(kStringEncodingMask == kAsciiStringTag); | 12460 ASSERT(kStringEncodingMask == kAsciiStringTag); |
12453 __ test(ecx, Immediate(kAsciiStringTag)); | 12461 __ test(ecx, Immediate(kAsciiStringTag)); |
12454 __ j(zero, &non_ascii_string_add_flat_result); | 12462 __ j(zero, &non_ascii_string_add_flat_result); |
12455 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12463 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12456 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12464 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12457 __ test(ecx, Immediate(kAsciiStringTag)); | 12465 __ test(ecx, Immediate(kAsciiStringTag)); |
12458 __ j(zero, &string_add_runtime); | 12466 __ j(zero, &string_add_runtime); |
12459 | 12467 |
12460 __ bind(&make_flat_ascii_string); | 12468 __ bind(&make_flat_ascii_string); |
12461 // Both strings are ascii strings. As they are short they are both flat. | 12469 // Both strings are ascii strings. As they are short they are both flat. |
12462 // ebx: length of resulting flat string | 12470 // ebx: length of resulting flat string as a smi |
| 12471 __ SmiUntag(ebx); |
12463 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 12472 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
12464 // eax: result string | 12473 // eax: result string |
12465 __ mov(ecx, eax); | 12474 __ mov(ecx, eax); |
12466 // Locate first character of result. | 12475 // Locate first character of result. |
12467 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12476 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12468 // Load first argument and locate first character. | 12477 // Load first argument and locate first character. |
12469 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 12478 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
12470 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12479 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12480 __ SmiUntag(edi); |
12471 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12481 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12472 // eax: result string | 12482 // eax: result string |
12473 // ecx: first character of result | 12483 // ecx: first character of result |
12474 // edx: first char of first argument | 12484 // edx: first char of first argument |
12475 // edi: length of first argument | 12485 // edi: length of first argument |
12476 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 12486 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
12477 // Load second argument and locate first character. | 12487 // Load second argument and locate first character. |
12478 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 12488 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
12479 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12489 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12490 __ SmiUntag(edi); |
12480 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12491 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12481 // eax: result string | 12492 // eax: result string |
12482 // ecx: next character of result | 12493 // ecx: next character of result |
12483 // edx: first char of second argument | 12494 // edx: first char of second argument |
12484 // edi: length of second argument | 12495 // edi: length of second argument |
12485 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 12496 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
12486 __ IncrementCounter(&Counters::string_add_native, 1); | 12497 __ IncrementCounter(&Counters::string_add_native, 1); |
12487 __ ret(2 * kPointerSize); | 12498 __ ret(2 * kPointerSize); |
12488 | 12499 |
12489 // Handle creating a flat two byte result. | 12500 // Handle creating a flat two byte result. |
12490 // eax: first string - known to be two byte | 12501 // eax: first string - known to be two byte |
12491 // ebx: length of resulting flat string | 12502 // ebx: length of resulting flat string as a smi |
12492 // edx: second string | 12503 // edx: second string |
12493 __ bind(&non_ascii_string_add_flat_result); | 12504 __ bind(&non_ascii_string_add_flat_result); |
12494 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12505 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12495 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12506 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12496 __ and_(ecx, kAsciiStringTag); | 12507 __ and_(ecx, kAsciiStringTag); |
12497 __ j(not_zero, &string_add_runtime); | 12508 __ j(not_zero, &string_add_runtime); |
12498 // Both strings are two byte strings. As they are short they are both | 12509 // Both strings are two byte strings. As they are short they are both |
12499 // flat. | 12510 // flat. |
| 12511 __ SmiUntag(ebx); |
12500 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 12512 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
12501 // eax: result string | 12513 // eax: result string |
12502 __ mov(ecx, eax); | 12514 __ mov(ecx, eax); |
12503 // Locate first character of result. | 12515 // Locate first character of result. |
12504 __ add(Operand(ecx), | 12516 __ add(Operand(ecx), |
12505 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 12517 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
12506 // Load first argument and locate first character. | 12518 // Load first argument and locate first character. |
12507 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 12519 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
12508 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12520 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12521 __ SmiUntag(edi); |
12509 __ add(Operand(edx), | 12522 __ add(Operand(edx), |
12510 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 12523 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
12511 // eax: result string | 12524 // eax: result string |
12512 // ecx: first character of result | 12525 // ecx: first character of result |
12513 // edx: first char of first argument | 12526 // edx: first char of first argument |
12514 // edi: length of first argument | 12527 // edi: length of first argument |
12515 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 12528 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
12516 // Load second argument and locate first character. | 12529 // Load second argument and locate first character. |
12517 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 12530 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
12518 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12531 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12532 __ SmiUntag(edi); |
12519 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12533 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
12520 // eax: result string | 12534 // eax: result string |
12521 // ecx: next character of result | 12535 // ecx: next character of result |
12522 // edx: first char of second argument | 12536 // edx: first char of second argument |
12523 // edi: length of second argument | 12537 // edi: length of second argument |
12524 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 12538 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
12525 __ IncrementCounter(&Counters::string_add_native, 1); | 12539 __ IncrementCounter(&Counters::string_add_native, 1); |
12526 __ ret(2 * kPointerSize); | 12540 __ ret(2 * kPointerSize); |
12527 | 12541 |
12528 // Just jump to runtime to add the two strings. | 12542 // Just jump to runtime to add the two strings. |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12693 FieldOperand(symbol_table, | 12707 FieldOperand(symbol_table, |
12694 scratch, | 12708 scratch, |
12695 times_pointer_size, | 12709 times_pointer_size, |
12696 SymbolTable::kElementsStartOffset)); | 12710 SymbolTable::kElementsStartOffset)); |
12697 | 12711 |
12698 // If entry is undefined no string with this hash can be found. | 12712 // If entry is undefined no string with this hash can be found. |
12699 __ cmp(candidate, Factory::undefined_value()); | 12713 __ cmp(candidate, Factory::undefined_value()); |
12700 __ j(equal, not_found); | 12714 __ j(equal, not_found); |
12701 | 12715 |
12702 // If length is not 2 the string is not a candidate. | 12716 // If length is not 2 the string is not a candidate. |
12703 __ cmp(FieldOperand(candidate, String::kLengthOffset), Immediate(2)); | 12717 __ cmp(FieldOperand(candidate, String::kLengthOffset), |
| 12718 Immediate(Smi::FromInt(2))); |
12704 __ j(not_equal, &next_probe[i]); | 12719 __ j(not_equal, &next_probe[i]); |
12705 | 12720 |
12706 // As we are out of registers save the mask on the stack and use that | 12721 // As we are out of registers save the mask on the stack and use that |
12707 // register as a temporary. | 12722 // register as a temporary. |
12708 __ push(mask); | 12723 __ push(mask); |
12709 Register temp = mask; | 12724 Register temp = mask; |
12710 | 12725 |
12711 // Check that the candidate is a non-external ascii string. | 12726 // Check that the candidate is a non-external ascii string. |
12712 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); | 12727 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); |
12713 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | 12728 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12962 | 12977 |
12963 Register min_length = scratch1; | 12978 Register min_length = scratch1; |
12964 | 12979 |
12965 // If either length is zero, just compare lengths. | 12980 // If either length is zero, just compare lengths. |
12966 __ test(min_length, Operand(min_length)); | 12981 __ test(min_length, Operand(min_length)); |
12967 __ j(zero, &compare_lengths); | 12982 __ j(zero, &compare_lengths); |
12968 | 12983 |
12969 // Change index to run from -min_length to -1 by adding min_length | 12984 // Change index to run from -min_length to -1 by adding min_length |
12970 // to string start. This means that loop ends when index reaches zero, | 12985 // to string start. This means that loop ends when index reaches zero, |
12971 // which doesn't need an additional compare. | 12986 // which doesn't need an additional compare. |
| 12987 __ SmiUntag(min_length); |
12972 __ lea(left, | 12988 __ lea(left, |
12973 FieldOperand(left, | 12989 FieldOperand(left, |
12974 min_length, times_1, | 12990 min_length, times_1, |
12975 SeqAsciiString::kHeaderSize)); | 12991 SeqAsciiString::kHeaderSize)); |
12976 __ lea(right, | 12992 __ lea(right, |
12977 FieldOperand(right, | 12993 FieldOperand(right, |
12978 min_length, times_1, | 12994 min_length, times_1, |
12979 SeqAsciiString::kHeaderSize)); | 12995 SeqAsciiString::kHeaderSize)); |
12980 __ neg(min_length); | 12996 __ neg(min_length); |
12981 | 12997 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13048 | 13064 |
13049 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 13065 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
13050 // tagged as a small integer. | 13066 // tagged as a small integer. |
13051 __ bind(&runtime); | 13067 __ bind(&runtime); |
13052 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 13068 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
13053 } | 13069 } |
13054 | 13070 |
13055 #undef __ | 13071 #undef __ |
13056 | 13072 |
13057 } } // namespace v8::internal | 13073 } } // namespace v8::internal |
OLD | NEW |