| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 3940 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3951 __ AssertString(r0); | 3951 __ AssertString(r0); |
| 3952 | 3952 |
| 3953 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); | 3953 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); |
| 3954 __ IndexFromHash(r0, r0); | 3954 __ IndexFromHash(r0, r0); |
| 3955 | 3955 |
| 3956 context()->Plug(r0); | 3956 context()->Plug(r0); |
| 3957 } | 3957 } |
| 3958 | 3958 |
| 3959 | 3959 |
| 3960 void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { | 3960 void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { |
| 3961 Label bailout, done, one_char_separator, long_separator, | 3961 Label bailout, done, one_char_separator, long_separator, non_trivial_array, |
| 3962 non_trivial_array, not_size_one_array, loop, | 3962 not_size_one_array, loop, empty_separator_loop, one_char_separator_loop, |
| 3963 empty_separator_loop, one_char_separator_loop, | |
| 3964 one_char_separator_loop_entry, long_separator_loop; | 3963 one_char_separator_loop_entry, long_separator_loop; |
| 3965 ZoneList<Expression*>* args = expr->arguments(); | 3964 ZoneList<Expression*>* args = expr->arguments(); |
| 3966 ASSERT(args->length() == 2); | 3965 ASSERT(args->length() == 2); |
| 3967 VisitForStackValue(args->at(1)); | 3966 VisitForStackValue(args->at(1)); |
| 3968 VisitForAccumulatorValue(args->at(0)); | 3967 VisitForAccumulatorValue(args->at(0)); |
| 3969 | 3968 |
| 3970 // All aliases of the same register have disjoint lifetimes. | 3969 // All aliases of the same register have disjoint lifetimes. |
| 3971 Register array = r0; | 3970 Register array = r0; |
| 3972 Register elements = no_reg; // Will be r0. | 3971 Register elements = no_reg; // Will be r0. |
| 3973 Register result = no_reg; // Will be r0. | 3972 Register result = no_reg; // Will be r0. |
| 3974 Register separator = r1; | 3973 Register separator = r1; |
| 3975 Register array_length = r2; | 3974 Register array_length = r2; |
| 3976 Register result_pos = no_reg; // Will be r2 | 3975 Register result_pos = no_reg; // Will be r2 |
| 3977 Register string_length = r3; | 3976 Register string_length = r3; |
| 3978 Register string = r4; | 3977 Register string = r4; |
| 3979 Register element = r5; | 3978 Register element = r5; |
| 3980 Register elements_end = r6; | 3979 Register elements_end = r6; |
| 3981 Register scratch1 = r7; | 3980 Register scratch = r9; |
| 3982 Register scratch2 = r9; | |
| 3983 | 3981 |
| 3984 // Separator operand is on the stack. | 3982 // Separator operand is on the stack. |
| 3985 __ pop(separator); | 3983 __ pop(separator); |
| 3986 | 3984 |
| 3987 // Check that the array is a JSArray. | 3985 // Check that the array is a JSArray. |
| 3988 __ JumpIfSmi(array, &bailout); | 3986 __ JumpIfSmi(array, &bailout); |
| 3989 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE); | 3987 __ CompareObjectType(array, scratch, array_length, JS_ARRAY_TYPE); |
| 3990 __ b(ne, &bailout); | 3988 __ b(ne, &bailout); |
| 3991 | 3989 |
| 3992 // Check that the array has fast elements. | 3990 // Check that the array has fast elements. |
| 3993 __ CheckFastElements(scratch1, scratch2, &bailout); | 3991 __ CheckFastElements(scratch, array_length, &bailout); |
| 3994 | 3992 |
| 3995 // If the array has length zero, return the empty string. | 3993 // If the array has length zero, return the empty string. |
| 3996 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); | 3994 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); |
| 3997 __ SmiUntag(array_length, SetCC); | 3995 __ SmiUntag(array_length, SetCC); |
| 3998 __ b(ne, &non_trivial_array); | 3996 __ b(ne, &non_trivial_array); |
| 3999 __ LoadRoot(r0, Heap::kempty_stringRootIndex); | 3997 __ LoadRoot(r0, Heap::kempty_stringRootIndex); |
| 4000 __ b(&done); | 3998 __ b(&done); |
| 4001 | 3999 |
| 4002 __ bind(&non_trivial_array); | 4000 __ bind(&non_trivial_array); |
| 4003 | 4001 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4020 // string_length: Accumulated sum of string lengths (smi). | 4018 // string_length: Accumulated sum of string lengths (smi). |
| 4021 // element: Current array element. | 4019 // element: Current array element. |
| 4022 // elements_end: Array end. | 4020 // elements_end: Array end. |
| 4023 if (generate_debug_code_) { | 4021 if (generate_debug_code_) { |
| 4024 __ cmp(array_length, Operand::Zero()); | 4022 __ cmp(array_length, Operand::Zero()); |
| 4025 __ Assert(gt, kNoEmptyArraysHereInEmitFastAsciiArrayJoin); | 4023 __ Assert(gt, kNoEmptyArraysHereInEmitFastAsciiArrayJoin); |
| 4026 } | 4024 } |
| 4027 __ bind(&loop); | 4025 __ bind(&loop); |
| 4028 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4026 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 4029 __ JumpIfSmi(string, &bailout); | 4027 __ JumpIfSmi(string, &bailout); |
| 4030 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); | 4028 __ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 4031 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | 4029 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 4032 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); | 4030 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout); |
| 4033 __ ldr(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); | 4031 __ ldr(scratch, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); |
| 4034 __ add(string_length, string_length, Operand(scratch1), SetCC); | 4032 __ add(string_length, string_length, Operand(scratch), SetCC); |
| 4035 __ b(vs, &bailout); | 4033 __ b(vs, &bailout); |
| 4036 __ cmp(element, elements_end); | 4034 __ cmp(element, elements_end); |
| 4037 __ b(lt, &loop); | 4035 __ b(lt, &loop); |
| 4038 | 4036 |
| 4039 // If array_length is 1, return elements[0], a string. | 4037 // If array_length is 1, return elements[0], a string. |
| 4040 __ cmp(array_length, Operand(1)); | 4038 __ cmp(array_length, Operand(1)); |
| 4041 __ b(ne, ¬_size_one_array); | 4039 __ b(ne, ¬_size_one_array); |
| 4042 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); | 4040 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); |
| 4043 __ b(&done); | 4041 __ b(&done); |
| 4044 | 4042 |
| 4045 __ bind(¬_size_one_array); | 4043 __ bind(¬_size_one_array); |
| 4046 | 4044 |
| 4047 // Live values in registers: | 4045 // Live values in registers: |
| 4048 // separator: Separator string | 4046 // separator: Separator string |
| 4049 // array_length: Length of the array. | 4047 // array_length: Length of the array. |
| 4050 // string_length: Sum of string lengths (smi). | 4048 // string_length: Sum of string lengths (smi). |
| 4051 // elements: FixedArray of strings. | 4049 // elements: FixedArray of strings. |
| 4052 | 4050 |
| 4053 // Check that the separator is a flat ASCII string. | 4051 // Check that the separator is a flat ASCII string. |
| 4054 __ JumpIfSmi(separator, &bailout); | 4052 __ JumpIfSmi(separator, &bailout); |
| 4055 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset)); | 4053 __ ldr(scratch, FieldMemOperand(separator, HeapObject::kMapOffset)); |
| 4056 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | 4054 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 4057 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); | 4055 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout); |
| 4058 | 4056 |
| 4059 // Add (separator length times array_length) - separator length to the | 4057 // Add (separator length times array_length) - separator length to the |
| 4060 // string_length to get the length of the result string. array_length is not | 4058 // string_length to get the length of the result string. array_length is not |
| 4061 // smi but the other values are, so the result is a smi | 4059 // smi but the other values are, so the result is a smi |
| 4062 __ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); | 4060 __ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); |
| 4063 __ sub(string_length, string_length, Operand(scratch1)); | 4061 __ sub(string_length, string_length, Operand(scratch)); |
| 4064 __ smull(scratch2, ip, array_length, scratch1); | 4062 __ smull(scratch, ip, array_length, scratch); |
| 4065 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are | 4063 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are |
| 4066 // zero. | 4064 // zero. |
| 4067 __ cmp(ip, Operand::Zero()); | 4065 __ cmp(ip, Operand::Zero()); |
| 4068 __ b(ne, &bailout); | 4066 __ b(ne, &bailout); |
| 4069 __ tst(scratch2, Operand(0x80000000)); | 4067 __ tst(scratch, Operand(0x80000000)); |
| 4070 __ b(ne, &bailout); | 4068 __ b(ne, &bailout); |
| 4071 __ add(string_length, string_length, Operand(scratch2), SetCC); | 4069 __ add(string_length, string_length, Operand(scratch), SetCC); |
| 4072 __ b(vs, &bailout); | 4070 __ b(vs, &bailout); |
| 4073 __ SmiUntag(string_length); | 4071 __ SmiUntag(string_length); |
| 4074 | 4072 |
| 4075 // Get first element in the array to free up the elements register to be used | 4073 // Get first element in the array to free up the elements register to be used |
| 4076 // for the result. | 4074 // for the result. |
| 4077 __ add(element, | 4075 __ add(element, |
| 4078 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 4076 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 4079 result = elements; // End of live range for elements. | 4077 result = elements; // End of live range for elements. |
| 4080 elements = no_reg; | 4078 elements = no_reg; |
| 4081 // Live values in registers: | 4079 // Live values in registers: |
| 4082 // element: First array element | 4080 // element: First array element |
| 4083 // separator: Separator string | 4081 // separator: Separator string |
| 4084 // string_length: Length of result string (not smi) | 4082 // string_length: Length of result string (not smi) |
| 4085 // array_length: Length of the array. | 4083 // array_length: Length of the array. |
| 4086 __ AllocateAsciiString(result, | 4084 __ AllocateAsciiString(result, |
| 4087 string_length, | 4085 string_length, |
| 4088 scratch1, | 4086 scratch, |
| 4089 scratch2, | 4087 string, // used as scratch |
| 4090 elements_end, | 4088 elements_end, // used as scratch |
| 4091 &bailout); | 4089 &bailout); |
| 4092 // Prepare for looping. Set up elements_end to end of the array. Set | 4090 // Prepare for looping. Set up elements_end to end of the array. Set |
| 4093 // result_pos to the position of the result where to write the first | 4091 // result_pos to the position of the result where to write the first |
| 4094 // character. | 4092 // character. |
| 4095 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); | 4093 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); |
| 4096 result_pos = array_length; // End of live range for array_length. | 4094 result_pos = array_length; // End of live range for array_length. |
| 4097 array_length = no_reg; | 4095 array_length = no_reg; |
| 4098 __ add(result_pos, | 4096 __ add(result_pos, |
| 4099 result, | 4097 result, |
| 4100 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4098 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 4101 | 4099 |
| 4102 // Check the length of the separator. | 4100 // Check the length of the separator. |
| 4103 __ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); | 4101 __ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); |
| 4104 __ cmp(scratch1, Operand(Smi::FromInt(1))); | 4102 __ cmp(scratch, Operand(Smi::FromInt(1))); |
| 4105 __ b(eq, &one_char_separator); | 4103 __ b(eq, &one_char_separator); |
| 4106 __ b(gt, &long_separator); | 4104 __ b(gt, &long_separator); |
| 4107 | 4105 |
| 4108 // Empty separator case | 4106 // Empty separator case |
| 4109 __ bind(&empty_separator_loop); | 4107 __ bind(&empty_separator_loop); |
| 4110 // Live values in registers: | 4108 // Live values in registers: |
| 4111 // result_pos: the position to which we are currently copying characters. | 4109 // result_pos: the position to which we are currently copying characters. |
| 4112 // element: Current array element. | 4110 // element: Current array element. |
| 4113 // elements_end: Array end. | 4111 // elements_end: Array end. |
| 4114 | 4112 |
| 4115 // Copy next array element to the result. | 4113 // Copy next array element to the result. |
| 4116 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4114 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 4117 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); | 4115 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| 4118 __ SmiUntag(string_length); | 4116 __ SmiUntag(string_length); |
| 4119 __ add(string, | 4117 __ add(string, |
| 4120 string, | 4118 string, |
| 4121 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4119 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 4122 __ CopyBytes(string, result_pos, string_length, scratch1); | 4120 __ CopyBytes(string, result_pos, string_length, scratch); |
| 4123 __ cmp(element, elements_end); | 4121 __ cmp(element, elements_end); |
| 4124 __ b(lt, &empty_separator_loop); // End while (element < elements_end). | 4122 __ b(lt, &empty_separator_loop); // End while (element < elements_end). |
| 4125 ASSERT(result.is(r0)); | 4123 ASSERT(result.is(r0)); |
| 4126 __ b(&done); | 4124 __ b(&done); |
| 4127 | 4125 |
| 4128 // One-character separator case | 4126 // One-character separator case |
| 4129 __ bind(&one_char_separator); | 4127 __ bind(&one_char_separator); |
| 4130 // Replace separator with its ASCII character value. | 4128 // Replace separator with its ASCII character value. |
| 4131 __ ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); | 4129 __ ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); |
| 4132 // Jump into the loop after the code that copies the separator, so the first | 4130 // Jump into the loop after the code that copies the separator, so the first |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4144 __ strb(separator, MemOperand(result_pos, 1, PostIndex)); | 4142 __ strb(separator, MemOperand(result_pos, 1, PostIndex)); |
| 4145 | 4143 |
| 4146 // Copy next array element to the result. | 4144 // Copy next array element to the result. |
| 4147 __ bind(&one_char_separator_loop_entry); | 4145 __ bind(&one_char_separator_loop_entry); |
| 4148 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4146 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 4149 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); | 4147 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| 4150 __ SmiUntag(string_length); | 4148 __ SmiUntag(string_length); |
| 4151 __ add(string, | 4149 __ add(string, |
| 4152 string, | 4150 string, |
| 4153 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4151 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 4154 __ CopyBytes(string, result_pos, string_length, scratch1); | 4152 __ CopyBytes(string, result_pos, string_length, scratch); |
| 4155 __ cmp(element, elements_end); | 4153 __ cmp(element, elements_end); |
| 4156 __ b(lt, &one_char_separator_loop); // End while (element < elements_end). | 4154 __ b(lt, &one_char_separator_loop); // End while (element < elements_end). |
| 4157 ASSERT(result.is(r0)); | 4155 ASSERT(result.is(r0)); |
| 4158 __ b(&done); | 4156 __ b(&done); |
| 4159 | 4157 |
| 4160 // Long separator case (separator is more than one character). Entry is at the | 4158 // Long separator case (separator is more than one character). Entry is at the |
| 4161 // label long_separator below. | 4159 // label long_separator below. |
| 4162 __ bind(&long_separator_loop); | 4160 __ bind(&long_separator_loop); |
| 4163 // Live values in registers: | 4161 // Live values in registers: |
| 4164 // result_pos: the position to which we are currently copying characters. | 4162 // result_pos: the position to which we are currently copying characters. |
| 4165 // element: Current array element. | 4163 // element: Current array element. |
| 4166 // elements_end: Array end. | 4164 // elements_end: Array end. |
| 4167 // separator: Separator string. | 4165 // separator: Separator string. |
| 4168 | 4166 |
| 4169 // Copy the separator to the result. | 4167 // Copy the separator to the result. |
| 4170 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset)); | 4168 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset)); |
| 4171 __ SmiUntag(string_length); | 4169 __ SmiUntag(string_length); |
| 4172 __ add(string, | 4170 __ add(string, |
| 4173 separator, | 4171 separator, |
| 4174 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4172 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 4175 __ CopyBytes(string, result_pos, string_length, scratch1); | 4173 __ CopyBytes(string, result_pos, string_length, scratch); |
| 4176 | 4174 |
| 4177 __ bind(&long_separator); | 4175 __ bind(&long_separator); |
| 4178 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4176 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 4179 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); | 4177 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| 4180 __ SmiUntag(string_length); | 4178 __ SmiUntag(string_length); |
| 4181 __ add(string, | 4179 __ add(string, |
| 4182 string, | 4180 string, |
| 4183 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4181 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 4184 __ CopyBytes(string, result_pos, string_length, scratch1); | 4182 __ CopyBytes(string, result_pos, string_length, scratch); |
| 4185 __ cmp(element, elements_end); | 4183 __ cmp(element, elements_end); |
| 4186 __ b(lt, &long_separator_loop); // End while (element < elements_end). | 4184 __ b(lt, &long_separator_loop); // End while (element < elements_end). |
| 4187 ASSERT(result.is(r0)); | 4185 ASSERT(result.is(r0)); |
| 4188 __ b(&done); | 4186 __ b(&done); |
| 4189 | 4187 |
| 4190 __ bind(&bailout); | 4188 __ bind(&bailout); |
| 4191 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 4189 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 4192 __ bind(&done); | 4190 __ bind(&done); |
| 4193 context()->Plug(r0); | 4191 context()->Plug(r0); |
| 4194 } | 4192 } |
| (...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4884 *context_length = 0; | 4882 *context_length = 0; |
| 4885 return previous_; | 4883 return previous_; |
| 4886 } | 4884 } |
| 4887 | 4885 |
| 4888 | 4886 |
| 4889 #undef __ | 4887 #undef __ |
| 4890 | 4888 |
| 4891 } } // namespace v8::internal | 4889 } } // namespace v8::internal |
| 4892 | 4890 |
| 4893 #endif // V8_TARGET_ARCH_ARM | 4891 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |