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 3948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3959 __ AssertString(r0); | 3959 __ AssertString(r0); |
3960 | 3960 |
3961 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); | 3961 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); |
3962 __ IndexFromHash(r0, r0); | 3962 __ IndexFromHash(r0, r0); |
3963 | 3963 |
3964 context()->Plug(r0); | 3964 context()->Plug(r0); |
3965 } | 3965 } |
3966 | 3966 |
3967 | 3967 |
3968 void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { | 3968 void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { |
3969 Label bailout, done, one_char_separator, long_separator, | 3969 Label bailout, pop_and_bailout, done, one_char_separator, |
3970 non_trivial_array, not_size_one_array, loop, | 3970 long_separator, non_trivial_array, not_size_one_array, loop, |
3971 empty_separator_loop, one_char_separator_loop, | 3971 empty_separator_loop, one_char_separator_loop, |
3972 one_char_separator_loop_entry, long_separator_loop; | 3972 one_char_separator_loop_entry, long_separator_loop; |
3973 ZoneList<Expression*>* args = expr->arguments(); | 3973 ZoneList<Expression*>* args = expr->arguments(); |
3974 ASSERT(args->length() == 2); | 3974 ASSERT(args->length() == 2); |
3975 VisitForStackValue(args->at(1)); | 3975 VisitForStackValue(args->at(1)); |
3976 VisitForAccumulatorValue(args->at(0)); | 3976 VisitForAccumulatorValue(args->at(0)); |
3977 | 3977 |
3978 // All aliases of the same register have disjoint lifetimes. | 3978 // All aliases of the same register have disjoint lifetimes. |
3979 Register array = r0; | 3979 Register array = r0; |
3980 Register elements = no_reg; // Will be r0. | 3980 Register elements = no_reg; // Will be r0. |
3981 Register result = no_reg; // Will be r0. | 3981 Register result = no_reg; // Will be r0. |
3982 Register separator = r1; | 3982 Register separator = r1; |
3983 Register array_length = r2; | 3983 Register array_length = r2; |
3984 Register result_pos = no_reg; // Will be r2 | 3984 Register result_pos = no_reg; // Will be r2 |
3985 Register string_length = r3; | 3985 Register string_length = r3; |
3986 Register string = r4; | 3986 Register string = r4; |
3987 Register element = r5; | 3987 Register element = r5; |
3988 Register elements_end = r6; | 3988 Register elements_end = r6; |
3989 Register scratch1 = r7; | 3989 Register scratch = r9; |
3990 Register scratch2 = r9; | |
3991 | 3990 |
3992 // Separator operand is on the stack. | 3991 // Separator operand is on the stack. |
3993 __ pop(separator); | 3992 __ pop(separator); |
3994 | 3993 |
3995 // Check that the array is a JSArray. | 3994 // Check that the array is a JSArray. |
3996 __ JumpIfSmi(array, &bailout); | 3995 __ JumpIfSmi(array, &bailout); |
3997 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE); | 3996 __ CompareObjectType(array, scratch, array_length, JS_ARRAY_TYPE); |
3998 __ b(ne, &bailout); | 3997 __ b(ne, &bailout); |
3999 | 3998 |
4000 // Check that the array has fast elements. | 3999 // Check that the array has fast elements. |
4001 __ CheckFastElements(scratch1, scratch2, &bailout); | 4000 __ CheckFastElements(scratch, array_length, &bailout); |
4002 | 4001 |
4003 // If the array has length zero, return the empty string. | 4002 // If the array has length zero, return the empty string. |
4004 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); | 4003 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); |
4005 __ SmiUntag(array_length, SetCC); | 4004 __ SmiUntag(array_length, SetCC); |
4006 __ b(ne, &non_trivial_array); | 4005 __ b(ne, &non_trivial_array); |
4007 __ LoadRoot(r0, Heap::kempty_stringRootIndex); | 4006 __ LoadRoot(r0, Heap::kempty_stringRootIndex); |
4008 __ b(&done); | 4007 __ b(&done); |
4009 | 4008 |
4010 __ bind(&non_trivial_array); | 4009 __ bind(&non_trivial_array); |
4011 | 4010 |
(...skipping 16 matching lines...) Expand all Loading... | |
4028 // string_length: Accumulated sum of string lengths (smi). | 4027 // string_length: Accumulated sum of string lengths (smi). |
4029 // element: Current array element. | 4028 // element: Current array element. |
4030 // elements_end: Array end. | 4029 // elements_end: Array end. |
4031 if (generate_debug_code_) { | 4030 if (generate_debug_code_) { |
4032 __ cmp(array_length, Operand::Zero()); | 4031 __ cmp(array_length, Operand::Zero()); |
4033 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin"); | 4032 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin"); |
4034 } | 4033 } |
4035 __ bind(&loop); | 4034 __ bind(&loop); |
4036 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4035 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
4037 __ JumpIfSmi(string, &bailout); | 4036 __ JumpIfSmi(string, &bailout); |
4038 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); | 4037 __ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset)); |
4039 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | 4038 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
4040 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); | 4039 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout); |
4041 __ ldr(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); | 4040 __ ldr(scratch, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); |
4042 __ add(string_length, string_length, Operand(scratch1), SetCC); | 4041 __ add(string_length, string_length, Operand(scratch), SetCC); |
4043 __ b(vs, &bailout); | 4042 __ b(vs, &bailout); |
4044 __ cmp(element, elements_end); | 4043 __ cmp(element, elements_end); |
4045 __ b(lt, &loop); | 4044 __ b(lt, &loop); |
4046 | 4045 |
4047 // If array_length is 1, return elements[0], a string. | 4046 // If array_length is 1, return elements[0], a string. |
4048 __ cmp(array_length, Operand(1)); | 4047 __ cmp(array_length, Operand(1)); |
4049 __ b(ne, ¬_size_one_array); | 4048 __ b(ne, ¬_size_one_array); |
4050 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); | 4049 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); |
4051 __ b(&done); | 4050 __ b(&done); |
4052 | 4051 |
4053 __ bind(¬_size_one_array); | 4052 __ bind(¬_size_one_array); |
4054 | 4053 |
4055 // Live values in registers: | 4054 // Live values in registers: |
4056 // separator: Separator string | 4055 // separator: Separator string |
4057 // array_length: Length of the array. | 4056 // array_length: Length of the array. |
4058 // string_length: Sum of string lengths (smi). | 4057 // string_length: Sum of string lengths (smi). |
4059 // elements: FixedArray of strings. | 4058 // elements: FixedArray of strings. |
4060 | 4059 |
4061 // Check that the separator is a flat ASCII string. | 4060 // Check that the separator is a flat ASCII string. |
4062 __ JumpIfSmi(separator, &bailout); | 4061 __ JumpIfSmi(separator, &bailout); |
4063 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset)); | 4062 __ ldr(scratch, FieldMemOperand(separator, HeapObject::kMapOffset)); |
4064 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | 4063 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
4065 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); | 4064 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout); |
4066 | 4065 |
4067 // Add (separator length times array_length) - separator length to the | 4066 // Add (separator length times array_length) - separator length to the |
4068 // string_length to get the length of the result string. array_length is not | 4067 // string_length to get the length of the result string. array_length is not |
4069 // smi but the other values are, so the result is a smi | 4068 // smi but the other values are, so the result is a smi |
4070 __ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); | 4069 __ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); |
4071 __ sub(string_length, string_length, Operand(scratch1)); | 4070 __ sub(string_length, string_length, Operand(scratch)); |
4072 __ smull(scratch2, ip, array_length, scratch1); | 4071 __ smull(scratch, ip, array_length, scratch); |
4073 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are | 4072 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are |
4074 // zero. | 4073 // zero. |
4075 __ cmp(ip, Operand::Zero()); | 4074 __ cmp(ip, Operand::Zero()); |
4076 __ b(ne, &bailout); | 4075 __ b(ne, &bailout); |
4077 __ tst(scratch2, Operand(0x80000000)); | 4076 __ tst(scratch, Operand(0x80000000)); |
4078 __ b(ne, &bailout); | 4077 __ b(ne, &bailout); |
4079 __ add(string_length, string_length, Operand(scratch2), SetCC); | 4078 __ add(string_length, string_length, Operand(scratch), SetCC); |
4080 __ b(vs, &bailout); | 4079 __ b(vs, &bailout); |
4081 __ SmiUntag(string_length); | 4080 __ SmiUntag(string_length); |
4082 | 4081 |
4083 // Get first element in the array to free up the elements register to be used | 4082 // Get first element in the array to free up the elements register to be used |
4084 // for the result. | 4083 // for the result. |
4085 __ add(element, | 4084 __ add(element, |
4086 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 4085 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
4087 result = elements; // End of live range for elements. | 4086 result = elements; // End of live range for elements. |
4088 elements = no_reg; | 4087 elements = no_reg; |
4089 // Live values in registers: | 4088 // Live values in registers: |
4090 // element: First array element | 4089 // element: First array element |
4091 // separator: Separator string | 4090 // separator: Separator string |
4092 // string_length: Length of result string (not smi) | 4091 // string_length: Length of result string (not smi) |
4093 // array_length: Length of the array. | 4092 // array_length: Length of the array. |
4093 __ push(separator); // Push separator to reuse register as a scratch. | |
Rodolph Perfetta
2013/07/30 15:19:08
If the comment above is correct then r4 is availab
rmcilroy
2013/07/30 17:12:37
Nice catch! I spent ages looking for a free reg he
| |
4094 __ AllocateAsciiString(result, | 4094 __ AllocateAsciiString(result, |
4095 string_length, | 4095 string_length, |
4096 scratch1, | 4096 scratch, |
4097 scratch2, | 4097 separator, |
4098 elements_end, | 4098 elements_end, |
4099 &bailout); | 4099 &pop_and_bailout); |
4100 __ pop(separator); | |
4100 // Prepare for looping. Set up elements_end to end of the array. Set | 4101 // Prepare for looping. Set up elements_end to end of the array. Set |
4101 // result_pos to the position of the result where to write the first | 4102 // result_pos to the position of the result where to write the first |
4102 // character. | 4103 // character. |
4103 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); | 4104 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); |
4104 result_pos = array_length; // End of live range for array_length. | 4105 result_pos = array_length; // End of live range for array_length. |
4105 array_length = no_reg; | 4106 array_length = no_reg; |
4106 __ add(result_pos, | 4107 __ add(result_pos, |
4107 result, | 4108 result, |
4108 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4109 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4109 | 4110 |
4110 // Check the length of the separator. | 4111 // Check the length of the separator. |
4111 __ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); | 4112 __ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); |
4112 __ cmp(scratch1, Operand(Smi::FromInt(1))); | 4113 __ cmp(scratch, Operand(Smi::FromInt(1))); |
4113 __ b(eq, &one_char_separator); | 4114 __ b(eq, &one_char_separator); |
4114 __ b(gt, &long_separator); | 4115 __ b(gt, &long_separator); |
4115 | 4116 |
4116 // Empty separator case | 4117 // Empty separator case |
4117 __ bind(&empty_separator_loop); | 4118 __ bind(&empty_separator_loop); |
4118 // Live values in registers: | 4119 // Live values in registers: |
4119 // result_pos: the position to which we are currently copying characters. | 4120 // result_pos: the position to which we are currently copying characters. |
4120 // element: Current array element. | 4121 // element: Current array element. |
4121 // elements_end: Array end. | 4122 // elements_end: Array end. |
4122 | 4123 |
4123 // Copy next array element to the result. | 4124 // Copy next array element to the result. |
4124 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4125 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
4125 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); | 4126 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
4126 __ SmiUntag(string_length); | 4127 __ SmiUntag(string_length); |
4127 __ add(string, | 4128 __ add(string, |
4128 string, | 4129 string, |
4129 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4130 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4130 __ CopyBytes(string, result_pos, string_length, scratch1); | 4131 __ CopyBytes(string, result_pos, string_length, scratch); |
4131 __ cmp(element, elements_end); | 4132 __ cmp(element, elements_end); |
4132 __ b(lt, &empty_separator_loop); // End while (element < elements_end). | 4133 __ b(lt, &empty_separator_loop); // End while (element < elements_end). |
4133 ASSERT(result.is(r0)); | 4134 ASSERT(result.is(r0)); |
4134 __ b(&done); | 4135 __ b(&done); |
4135 | 4136 |
4136 // One-character separator case | 4137 // One-character separator case |
4137 __ bind(&one_char_separator); | 4138 __ bind(&one_char_separator); |
4138 // Replace separator with its ASCII character value. | 4139 // Replace separator with its ASCII character value. |
4139 __ ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); | 4140 __ ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); |
4140 // Jump into the loop after the code that copies the separator, so the first | 4141 // Jump into the loop after the code that copies the separator, so the first |
(...skipping 11 matching lines...) Expand all Loading... | |
4152 __ strb(separator, MemOperand(result_pos, 1, PostIndex)); | 4153 __ strb(separator, MemOperand(result_pos, 1, PostIndex)); |
4153 | 4154 |
4154 // Copy next array element to the result. | 4155 // Copy next array element to the result. |
4155 __ bind(&one_char_separator_loop_entry); | 4156 __ bind(&one_char_separator_loop_entry); |
4156 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4157 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
4157 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); | 4158 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
4158 __ SmiUntag(string_length); | 4159 __ SmiUntag(string_length); |
4159 __ add(string, | 4160 __ add(string, |
4160 string, | 4161 string, |
4161 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4162 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4162 __ CopyBytes(string, result_pos, string_length, scratch1); | 4163 __ CopyBytes(string, result_pos, string_length, scratch); |
4163 __ cmp(element, elements_end); | 4164 __ cmp(element, elements_end); |
4164 __ b(lt, &one_char_separator_loop); // End while (element < elements_end). | 4165 __ b(lt, &one_char_separator_loop); // End while (element < elements_end). |
4165 ASSERT(result.is(r0)); | 4166 ASSERT(result.is(r0)); |
4166 __ b(&done); | 4167 __ b(&done); |
4167 | 4168 |
4168 // Long separator case (separator is more than one character). Entry is at the | 4169 // Long separator case (separator is more than one character). Entry is at the |
4169 // label long_separator below. | 4170 // label long_separator below. |
4170 __ bind(&long_separator_loop); | 4171 __ bind(&long_separator_loop); |
4171 // Live values in registers: | 4172 // Live values in registers: |
4172 // result_pos: the position to which we are currently copying characters. | 4173 // result_pos: the position to which we are currently copying characters. |
4173 // element: Current array element. | 4174 // element: Current array element. |
4174 // elements_end: Array end. | 4175 // elements_end: Array end. |
4175 // separator: Separator string. | 4176 // separator: Separator string. |
4176 | 4177 |
4177 // Copy the separator to the result. | 4178 // Copy the separator to the result. |
4178 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset)); | 4179 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset)); |
4179 __ SmiUntag(string_length); | 4180 __ SmiUntag(string_length); |
4180 __ add(string, | 4181 __ add(string, |
4181 separator, | 4182 separator, |
4182 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4183 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4183 __ CopyBytes(string, result_pos, string_length, scratch1); | 4184 __ CopyBytes(string, result_pos, string_length, scratch); |
4184 | 4185 |
4185 __ bind(&long_separator); | 4186 __ bind(&long_separator); |
4186 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); | 4187 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
4187 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); | 4188 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
4188 __ SmiUntag(string_length); | 4189 __ SmiUntag(string_length); |
4189 __ add(string, | 4190 __ add(string, |
4190 string, | 4191 string, |
4191 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4192 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4192 __ CopyBytes(string, result_pos, string_length, scratch1); | 4193 __ CopyBytes(string, result_pos, string_length, scratch); |
4193 __ cmp(element, elements_end); | 4194 __ cmp(element, elements_end); |
4194 __ b(lt, &long_separator_loop); // End while (element < elements_end). | 4195 __ b(lt, &long_separator_loop); // End while (element < elements_end). |
4195 ASSERT(result.is(r0)); | 4196 ASSERT(result.is(r0)); |
4196 __ b(&done); | 4197 __ b(&done); |
4197 | 4198 |
4199 __ bind(&pop_and_bailout); | |
4200 __ Drop(1, al); | |
4198 __ bind(&bailout); | 4201 __ bind(&bailout); |
4199 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 4202 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
4200 __ bind(&done); | 4203 __ bind(&done); |
4201 context()->Plug(r0); | 4204 context()->Plug(r0); |
4202 } | 4205 } |
4203 | 4206 |
4204 | 4207 |
4205 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 4208 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
4206 Handle<String> name = expr->name(); | 4209 Handle<String> name = expr->name(); |
4207 if (name->length() > 0 && name->Get(0) == '_') { | 4210 if (name->length() > 0 && name->Get(0) == '_') { |
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4915 *context_length = 0; | 4918 *context_length = 0; |
4916 return previous_; | 4919 return previous_; |
4917 } | 4920 } |
4918 | 4921 |
4919 | 4922 |
4920 #undef __ | 4923 #undef __ |
4921 | 4924 |
4922 } } // namespace v8::internal | 4925 } } // namespace v8::internal |
4923 | 4926 |
4924 #endif // V8_TARGET_ARCH_ARM | 4927 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |