| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
| 9 | 9 |
| 10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
| 11 #include "vm/cpu.h" | 11 #include "vm/cpu.h" |
| 12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/symbols.h" | 15 #include "vm/symbols.h" |
| 16 | 16 |
| 17 namespace dart { | 17 namespace dart { |
| 18 | 18 |
| 19 DECLARE_FLAG(bool, enable_type_checks); | 19 DECLARE_FLAG(bool, enable_type_checks); |
| 20 | 20 |
| 21 | 21 |
| 22 #define __ assembler-> | 22 #define __ assembler-> |
| 23 | 23 |
| 24 | 24 |
| 25 void Intrinsifier::Array_getLength(Assembler* assembler) { | 25 void Intrinsifier::ObjectArrayLength(Assembler* assembler) { |
| 26 __ ldr(R0, Address(SP, 0 * kWordSize)); | 26 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 27 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 27 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 28 __ Ret(); | 28 __ Ret(); |
| 29 } | 29 } |
| 30 | 30 |
| 31 | 31 |
| 32 void Intrinsifier::ImmutableList_getLength(Assembler* assembler) { | 32 void Intrinsifier::ImmutableArrayLength(Assembler* assembler) { |
| 33 Array_getLength(assembler); | 33 ObjectArrayLength(assembler); |
| 34 } | 34 } |
| 35 | 35 |
| 36 | 36 |
| 37 void Intrinsifier::Array_getIndexed(Assembler* assembler) { | 37 void Intrinsifier::ObjectArrayGetIndexed(Assembler* assembler) { |
| 38 Label fall_through; | 38 Label fall_through; |
| 39 | 39 |
| 40 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 40 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 41 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 41 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 42 | 42 |
| 43 __ tst(R0, Operand(kSmiTagMask)); | 43 __ tst(R0, Operand(kSmiTagMask)); |
| 44 __ b(&fall_through, NE); // Index is not an smi, fall through | 44 __ b(&fall_through, NE); // Index is not an smi, fall through |
| 45 | 45 |
| 46 // Range check. | 46 // Range check. |
| 47 __ ldr(R6, FieldAddress(R1, Array::length_offset())); | 47 __ ldr(R6, FieldAddress(R1, Array::length_offset())); |
| 48 __ cmp(R0, Operand(R6)); | 48 __ cmp(R0, Operand(R6)); |
| 49 | 49 |
| 50 ASSERT(kSmiTagShift == 1); | 50 ASSERT(kSmiTagShift == 1); |
| 51 // array element at R1 + R0*2 + Array::data_offset - 1 | 51 // array element at R1 + R0*2 + Array::data_offset - 1 |
| 52 __ add(R6, R1, Operand(R0, LSL, 1), CC); | 52 __ add(R6, R1, Operand(R0, LSL, 1), CC); |
| 53 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); | 53 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); |
| 54 __ bx(LR, CC); | 54 __ bx(LR, CC); |
| 55 __ Bind(&fall_through); | 55 __ Bind(&fall_through); |
| 56 } | 56 } |
| 57 | 57 |
| 58 | 58 |
| 59 void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) { | 59 void Intrinsifier::ImmutableArrayGetIndexed(Assembler* assembler) { |
| 60 Array_getIndexed(assembler); | 60 ObjectArrayGetIndexed(assembler); |
| 61 } | 61 } |
| 62 | 62 |
| 63 | 63 |
| 64 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 64 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 65 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 65 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 66 const Class& cls = Class::Handle( | 66 const Class& cls = Class::Handle( |
| 67 core_lib.LookupClassAllowPrivate(Symbols::_List())); | 67 core_lib.LookupClassAllowPrivate(Symbols::_List())); |
| 68 ASSERT(!cls.IsNull()); | 68 ASSERT(!cls.IsNull()); |
| 69 ASSERT(cls.NumTypeArguments() == 1); | 69 ASSERT(cls.NumTypeArguments() == 1); |
| 70 const intptr_t field_offset = cls.type_arguments_field_offset(); | 70 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 71 ASSERT(field_offset != Class::kNoTypeArguments); | 71 ASSERT(field_offset != Class::kNoTypeArguments); |
| 72 return field_offset; | 72 return field_offset; |
| 73 } | 73 } |
| 74 | 74 |
| 75 | 75 |
| 76 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 76 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
| 77 // update. Array length is always a Smi. | 77 // update. Array length is always a Smi. |
| 78 void Intrinsifier::Array_setIndexed(Assembler* assembler) { | 78 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) { |
| 79 Label fall_through; | 79 Label fall_through; |
| 80 | 80 |
| 81 if (FLAG_enable_type_checks) { | 81 if (FLAG_enable_type_checks) { |
| 82 const intptr_t type_args_field_offset = | 82 const intptr_t type_args_field_offset = |
| 83 ComputeObjectArrayTypeArgumentsOffset(); | 83 ComputeObjectArrayTypeArgumentsOffset(); |
| 84 // Inline simple tests (Smi, null), fallthrough if not positive. | 84 // Inline simple tests (Smi, null), fallthrough if not positive. |
| 85 const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null()); | 85 const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null()); |
| 86 Label checked_ok; | 86 Label checked_ok; |
| 87 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 87 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 88 | 88 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 __ add(R1, R0, Operand(R1, LSL, 1)); // R1 is Smi. | 130 __ add(R1, R0, Operand(R1, LSL, 1)); // R1 is Smi. |
| 131 __ StoreIntoObject(R0, FieldAddress(R1, Array::data_offset()), R2); | 131 __ StoreIntoObject(R0, FieldAddress(R1, Array::data_offset()), R2); |
| 132 // Caller is responsible for preserving the value if necessary. | 132 // Caller is responsible for preserving the value if necessary. |
| 133 __ Ret(); | 133 __ Ret(); |
| 134 __ Bind(&fall_through); | 134 __ Bind(&fall_through); |
| 135 } | 135 } |
| 136 | 136 |
| 137 | 137 |
| 138 // Allocate a GrowableObjectArray using the backing array specified. | 138 // Allocate a GrowableObjectArray using the backing array specified. |
| 139 // On stack: type argument (+1), data (+0). | 139 // On stack: type argument (+1), data (+0). |
| 140 void Intrinsifier::GrowableList_Allocate(Assembler* assembler) { | 140 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 141 // The newly allocated object is returned in R0. | 141 // The newly allocated object is returned in R0. |
| 142 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 142 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 143 const intptr_t kArrayOffset = 0 * kWordSize; | 143 const intptr_t kArrayOffset = 0 * kWordSize; |
| 144 Label fall_through; | 144 Label fall_through; |
| 145 | 145 |
| 146 // Try allocating in new space. | 146 // Try allocating in new space. |
| 147 const Class& cls = Class::Handle( | 147 const Class& cls = Class::Handle( |
| 148 Isolate::Current()->object_store()->growable_object_array_class()); | 148 Isolate::Current()->object_store()->growable_object_array_class()); |
| 149 __ TryAllocate(cls, &fall_through, R0, R1); | 149 __ TryAllocate(cls, &fall_through, R0, R1); |
| 150 | 150 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 166 | 166 |
| 167 // Set the length field in the growable array object to 0. | 167 // Set the length field in the growable array object to 0. |
| 168 __ LoadImmediate(R1, 0); | 168 __ LoadImmediate(R1, 0); |
| 169 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 169 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 170 __ Ret(); // Returns the newly allocated object in R0. | 170 __ Ret(); // Returns the newly allocated object in R0. |
| 171 | 171 |
| 172 __ Bind(&fall_through); | 172 __ Bind(&fall_through); |
| 173 } | 173 } |
| 174 | 174 |
| 175 | 175 |
| 176 void Intrinsifier::GrowableList_getLength(Assembler* assembler) { | 176 void Intrinsifier::GrowableArrayLength(Assembler* assembler) { |
| 177 __ ldr(R0, Address(SP, 0 * kWordSize)); | 177 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 178 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); | 178 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 179 __ Ret(); | 179 __ Ret(); |
| 180 } | 180 } |
| 181 | 181 |
| 182 | 182 |
| 183 void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) { | 183 void Intrinsifier::GrowableArrayCapacity(Assembler* assembler) { |
| 184 __ ldr(R0, Address(SP, 0 * kWordSize)); | 184 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 185 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); | 185 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); |
| 186 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 186 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 187 __ Ret(); | 187 __ Ret(); |
| 188 } | 188 } |
| 189 | 189 |
| 190 | 190 |
| 191 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { | 191 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { |
| 192 Label fall_through; | 192 Label fall_through; |
| 193 | 193 |
| 194 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 194 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 195 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 195 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 196 | 196 |
| 197 __ tst(R0, Operand(kSmiTagMask)); | 197 __ tst(R0, Operand(kSmiTagMask)); |
| 198 __ b(&fall_through, NE); // Index is not an smi, fall through | 198 __ b(&fall_through, NE); // Index is not an smi, fall through |
| 199 | 199 |
| 200 // Range check. | 200 // Range check. |
| 201 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); | 201 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); |
| 202 __ cmp(R0, Operand(R6)); | 202 __ cmp(R0, Operand(R6)); |
| 203 | 203 |
| 204 ASSERT(kSmiTagShift == 1); | 204 ASSERT(kSmiTagShift == 1); |
| 205 // array element at R6 + R0 * 2 + Array::data_offset - 1 | 205 // array element at R6 + R0 * 2 + Array::data_offset - 1 |
| 206 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data | 206 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data |
| 207 __ add(R6, R6, Operand(R0, LSL, 1), CC); | 207 __ add(R6, R6, Operand(R0, LSL, 1), CC); |
| 208 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); | 208 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); |
| 209 __ bx(LR, CC); | 209 __ bx(LR, CC); |
| 210 __ Bind(&fall_through); | 210 __ Bind(&fall_through); |
| 211 } | 211 } |
| 212 | 212 |
| 213 | 213 |
| 214 // Set value into growable object array at specified index. | 214 // Set value into growable object array at specified index. |
| 215 // On stack: growable array (+2), index (+1), value (+0). | 215 // On stack: growable array (+2), index (+1), value (+0). |
| 216 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { | 216 void Intrinsifier::GrowableArraySetIndexed(Assembler* assembler) { |
| 217 if (FLAG_enable_type_checks) { | 217 if (FLAG_enable_type_checks) { |
| 218 return; | 218 return; |
| 219 } | 219 } |
| 220 Label fall_through; | 220 Label fall_through; |
| 221 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 221 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 222 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. | 222 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 223 __ tst(R1, Operand(kSmiTagMask)); | 223 __ tst(R1, Operand(kSmiTagMask)); |
| 224 __ b(&fall_through, NE); // Non-smi index. | 224 __ b(&fall_through, NE); // Non-smi index. |
| 225 // Range check using _length field. | 225 // Range check using _length field. |
| 226 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); | 226 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 227 __ cmp(R1, Operand(R2)); | 227 __ cmp(R1, Operand(R2)); |
| 228 // Runtime throws exception. | 228 // Runtime throws exception. |
| 229 __ b(&fall_through, CS); | 229 __ b(&fall_through, CS); |
| 230 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. | 230 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. |
| 231 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 231 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 232 // Note that R1 is Smi, i.e, times 2. | 232 // Note that R1 is Smi, i.e, times 2. |
| 233 ASSERT(kSmiTagShift == 1); | 233 ASSERT(kSmiTagShift == 1); |
| 234 __ add(R1, R0, Operand(R1, LSL, 1)); | 234 __ add(R1, R0, Operand(R1, LSL, 1)); |
| 235 __ StoreIntoObject(R0, FieldAddress(R1, Array::data_offset()), R2); | 235 __ StoreIntoObject(R0, FieldAddress(R1, Array::data_offset()), R2); |
| 236 __ Ret(); | 236 __ Ret(); |
| 237 __ Bind(&fall_through); | 237 __ Bind(&fall_through); |
| 238 } | 238 } |
| 239 | 239 |
| 240 | 240 |
| 241 // Set length of growable object array. The length cannot | 241 // Set length of growable object array. The length cannot |
| 242 // be greater than the length of the data container. | 242 // be greater than the length of the data container. |
| 243 // On stack: growable array (+1), length (+0). | 243 // On stack: growable array (+1), length (+0). |
| 244 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { | 244 void Intrinsifier::GrowableArraySetLength(Assembler* assembler) { |
| 245 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 245 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 246 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. | 246 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. |
| 247 __ tst(R1, Operand(kSmiTagMask)); // Check for Smi. | 247 __ tst(R1, Operand(kSmiTagMask)); // Check for Smi. |
| 248 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ); | 248 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ); |
| 249 __ bx(LR, EQ); | 249 __ bx(LR, EQ); |
| 250 // Fall through on non-Smi. | 250 // Fall through on non-Smi. |
| 251 } | 251 } |
| 252 | 252 |
| 253 | 253 |
| 254 // Set data of growable object array. | 254 // Set data of growable object array. |
| 255 // On stack: growable array (+1), data (+0). | 255 // On stack: growable array (+1), data (+0). |
| 256 void Intrinsifier::GrowableList_setData(Assembler* assembler) { | 256 void Intrinsifier::GrowableArraySetData(Assembler* assembler) { |
| 257 if (FLAG_enable_type_checks) { | 257 if (FLAG_enable_type_checks) { |
| 258 return; | 258 return; |
| 259 } | 259 } |
| 260 Label fall_through; | 260 Label fall_through; |
| 261 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. | 261 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. |
| 262 // Check that data is an ObjectArray. | 262 // Check that data is an ObjectArray. |
| 263 __ tst(R1, Operand(kSmiTagMask)); | 263 __ tst(R1, Operand(kSmiTagMask)); |
| 264 __ b(&fall_through, EQ); // Data is Smi. | 264 __ b(&fall_through, EQ); // Data is Smi. |
| 265 __ CompareClassId(R1, kArrayCid, R0); | 265 __ CompareClassId(R1, kArrayCid, R0); |
| 266 __ b(&fall_through, NE); | 266 __ b(&fall_through, NE); |
| 267 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 267 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 268 __ StoreIntoObject(R0, | 268 __ StoreIntoObject(R0, |
| 269 FieldAddress(R0, GrowableObjectArray::data_offset()), | 269 FieldAddress(R0, GrowableObjectArray::data_offset()), |
| 270 R1); | 270 R1); |
| 271 __ Ret(); | 271 __ Ret(); |
| 272 __ Bind(&fall_through); | 272 __ Bind(&fall_through); |
| 273 } | 273 } |
| 274 | 274 |
| 275 | 275 |
| 276 // Add an element to growable array if it doesn't need to grow, otherwise | 276 // Add an element to growable array if it doesn't need to grow, otherwise |
| 277 // call into regular code. | 277 // call into regular code. |
| 278 // On stack: growable array (+1), value (+0). | 278 // On stack: growable array (+1), value (+0). |
| 279 void Intrinsifier::GrowableList_add(Assembler* assembler) { | 279 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
| 280 // In checked mode we need to type-check the incoming argument. | 280 // In checked mode we need to type-check the incoming argument. |
| 281 if (FLAG_enable_type_checks) { | 281 if (FLAG_enable_type_checks) { |
| 282 return; | 282 return; |
| 283 } | 283 } |
| 284 Label fall_through; | 284 Label fall_through; |
| 285 // R0: Array. | 285 // R0: Array. |
| 286 __ ldr(R0, Address(SP, 1 * kWordSize)); | 286 __ ldr(R0, Address(SP, 1 * kWordSize)); |
| 287 // R1: length. | 287 // R1: length. |
| 288 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 288 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 289 // R2: data. | 289 // R2: data. |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 __ cmp(R2, Operand(R1)); \ | 386 __ cmp(R2, Operand(R1)); \ |
| 387 __ str(R3, Address(R2, 0), CC); \ | 387 __ str(R3, Address(R2, 0), CC); \ |
| 388 __ add(R2, R2, Operand(kWordSize), CC); \ | 388 __ add(R2, R2, Operand(kWordSize), CC); \ |
| 389 __ b(&init_loop, CC); \ | 389 __ b(&init_loop, CC); \ |
| 390 \ | 390 \ |
| 391 __ Ret(); \ | 391 __ Ret(); \ |
| 392 __ Bind(&fall_through); \ | 392 __ Bind(&fall_through); \ |
| 393 | 393 |
| 394 | 394 |
| 395 // Gets the length of a TypedData. | 395 // Gets the length of a TypedData. |
| 396 void Intrinsifier::TypedData_getLength(Assembler* assembler) { | 396 void Intrinsifier::TypedDataLength(Assembler* assembler) { |
| 397 __ ldr(R0, Address(SP, 0 * kWordSize)); | 397 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 398 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); | 398 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); |
| 399 __ Ret(); | 399 __ Ret(); |
| 400 } | 400 } |
| 401 | 401 |
| 402 | 402 |
| 403 void Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) { | 403 void Intrinsifier::Uint8ArrayGetIndexed(Assembler* assembler) { |
| 404 Label fall_through; | 404 Label fall_through; |
| 405 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | 405 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. |
| 406 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | 406 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. |
| 407 __ tst(R0, Operand(kSmiTagMask)); | 407 __ tst(R0, Operand(kSmiTagMask)); |
| 408 __ b(&fall_through, NE); // Index is not a smi, fall through. | 408 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 409 | 409 |
| 410 // Range check. | 410 // Range check. |
| 411 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | 411 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); |
| 412 __ cmp(R0, Operand(R6)); | 412 __ cmp(R0, Operand(R6)); |
| 413 __ b(&fall_through, CS); | 413 __ b(&fall_through, CS); |
| 414 | 414 |
| 415 __ SmiUntag(R0); | 415 __ SmiUntag(R0); |
| 416 __ AddImmediate(R1, TypedData::data_offset() - kHeapObjectTag); | 416 __ AddImmediate(R1, TypedData::data_offset() - kHeapObjectTag); |
| 417 __ ldrb(R0, Address(R1, R0)); | 417 __ ldrb(R0, Address(R1, R0)); |
| 418 __ SmiTag(R0); | 418 __ SmiTag(R0); |
| 419 __ Ret(); | 419 __ Ret(); |
| 420 __ Bind(&fall_through); | 420 __ Bind(&fall_through); |
| 421 } | 421 } |
| 422 | 422 |
| 423 | 423 |
| 424 void Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) { | 424 void Intrinsifier::ExternalUint8ArrayGetIndexed(Assembler* assembler) { |
| 425 Label fall_through; | 425 Label fall_through; |
| 426 | 426 |
| 427 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | 427 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. |
| 428 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | 428 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. |
| 429 __ tst(R0, Operand(kSmiTagMask)); | 429 __ tst(R0, Operand(kSmiTagMask)); |
| 430 __ b(&fall_through, NE); // Index is not a smi, fall through. | 430 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 431 | 431 |
| 432 // Range check. | 432 // Range check. |
| 433 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | 433 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); |
| 434 __ cmp(R0, Operand(R6)); | 434 __ cmp(R0, Operand(R6)); |
| 435 __ b(&fall_through, CS); | 435 __ b(&fall_through, CS); |
| 436 | 436 |
| 437 __ LoadFromOffset(kWord, R1, R1, | 437 __ LoadFromOffset(kWord, R1, R1, |
| 438 ExternalTypedData::data_offset() - kHeapObjectTag); | 438 ExternalTypedData::data_offset() - kHeapObjectTag); |
| 439 __ SmiUntag(R0); | 439 __ SmiUntag(R0); |
| 440 __ ldrb(R0, Address(R1, R0)); | 440 __ ldrb(R0, Address(R1, R0)); |
| 441 __ SmiTag(R0); | 441 __ SmiTag(R0); |
| 442 __ Ret(); | 442 __ Ret(); |
| 443 __ Bind(&fall_through); | 443 __ Bind(&fall_through); |
| 444 } | 444 } |
| 445 | 445 |
| 446 | 446 |
| 447 void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) { | 447 void Intrinsifier::Float64ArrayGetIndexed(Assembler* assembler) { |
| 448 if (!TargetCPUFeatures::vfp_supported()) { | 448 if (!TargetCPUFeatures::vfp_supported()) { |
| 449 return; | 449 return; |
| 450 } | 450 } |
| 451 Label fall_through; | 451 Label fall_through; |
| 452 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | 452 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. |
| 453 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | 453 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. |
| 454 __ tst(R0, Operand(kSmiTagMask)); | 454 __ tst(R0, Operand(kSmiTagMask)); |
| 455 __ b(&fall_through, NE); // Index is not a smi, fall through. | 455 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 456 | 456 |
| 457 // Range check. | 457 // Range check. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 475 __ TryAllocate(double_class, | 475 __ TryAllocate(double_class, |
| 476 &fall_through, | 476 &fall_through, |
| 477 R0, // Result register. | 477 R0, // Result register. |
| 478 R1); | 478 R1); |
| 479 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 479 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 480 __ Ret(); | 480 __ Ret(); |
| 481 __ Bind(&fall_through); | 481 __ Bind(&fall_through); |
| 482 } | 482 } |
| 483 | 483 |
| 484 | 484 |
| 485 void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) { | 485 void Intrinsifier::Float64ArraySetIndexed(Assembler* assembler) { |
| 486 if (!TargetCPUFeatures::vfp_supported()) { | 486 if (!TargetCPUFeatures::vfp_supported()) { |
| 487 return; | 487 return; |
| 488 } | 488 } |
| 489 Label fall_through; | 489 Label fall_through; |
| 490 __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index. | 490 __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index. |
| 491 __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array. | 491 __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array. |
| 492 __ tst(R0, Operand(kSmiTagMask)); | 492 __ tst(R0, Operand(kSmiTagMask)); |
| 493 __ b(&fall_through, NE); // Index is not a smi, fall through. | 493 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 494 | 494 |
| 495 // Range check. | 495 // Range check. |
| (...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 // Check for negative zero by looking at the sign bit. | 1254 // Check for negative zero by looking at the sign bit. |
| 1255 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1. | 1255 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1. |
| 1256 __ mov(R1, Operand(R1, LSR, 31)); | 1256 __ mov(R1, Operand(R1, LSR, 31)); |
| 1257 __ tst(R1, Operand(1)); | 1257 __ tst(R1, Operand(1)); |
| 1258 __ b(&is_true, NE); // Sign bit set. | 1258 __ b(&is_true, NE); // Sign bit set. |
| 1259 __ b(&is_false); | 1259 __ b(&is_false); |
| 1260 } | 1260 } |
| 1261 } | 1261 } |
| 1262 | 1262 |
| 1263 | 1263 |
| 1264 void Intrinsifier::Double_toInt(Assembler* assembler) { | 1264 void Intrinsifier::DoubleToInteger(Assembler* assembler) { |
| 1265 if (TargetCPUFeatures::vfp_supported()) { | 1265 if (TargetCPUFeatures::vfp_supported()) { |
| 1266 Label fall_through; | 1266 Label fall_through; |
| 1267 | 1267 |
| 1268 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1268 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1269 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1269 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1270 | 1270 |
| 1271 // Explicit NaN check, since ARM gives an FPU exception if you try to | 1271 // Explicit NaN check, since ARM gives an FPU exception if you try to |
| 1272 // convert NaN to an int. | 1272 // convert NaN to an int. |
| 1273 __ vcmpd(D0, D0); | 1273 __ vcmpd(D0, D0); |
| 1274 __ vmstat(); | 1274 __ vmstat(); |
| 1275 __ b(&fall_through, VS); | 1275 __ b(&fall_through, VS); |
| 1276 | 1276 |
| 1277 __ vcvtid(S0, D0); | 1277 __ vcvtid(S0, D0); |
| 1278 __ vmovrs(R0, S0); | 1278 __ vmovrs(R0, S0); |
| 1279 // Overflow is signaled with minint. | 1279 // Overflow is signaled with minint. |
| 1280 // Check for overflow and that it fits into Smi. | 1280 // Check for overflow and that it fits into Smi. |
| 1281 __ CompareImmediate(R0, 0xC0000000); | 1281 __ CompareImmediate(R0, 0xC0000000); |
| 1282 __ SmiTag(R0, PL); | 1282 __ SmiTag(R0, PL); |
| 1283 __ bx(LR, PL); | 1283 __ bx(LR, PL); |
| 1284 __ Bind(&fall_through); | 1284 __ Bind(&fall_through); |
| 1285 } | 1285 } |
| 1286 } | 1286 } |
| 1287 | 1287 |
| 1288 | 1288 |
| 1289 void Intrinsifier::Math_sqrt(Assembler* assembler) { | 1289 void Intrinsifier::MathSqrt(Assembler* assembler) { |
| 1290 if (TargetCPUFeatures::vfp_supported()) { | 1290 if (TargetCPUFeatures::vfp_supported()) { |
| 1291 Label fall_through, is_smi, double_op; | 1291 Label fall_through, is_smi, double_op; |
| 1292 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1292 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1293 // Argument is double and is in R0. | 1293 // Argument is double and is in R0. |
| 1294 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); | 1294 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); |
| 1295 __ Bind(&double_op); | 1295 __ Bind(&double_op); |
| 1296 __ vsqrtd(D0, D1); | 1296 __ vsqrtd(D0, D1); |
| 1297 const Class& double_class = Class::Handle( | 1297 const Class& double_class = Class::Handle( |
| 1298 Isolate::Current()->object_store()->double_class()); | 1298 Isolate::Current()->object_store()->double_class()); |
| 1299 __ TryAllocate(double_class, &fall_through, R0, R1); // Result register. | 1299 __ TryAllocate(double_class, &fall_through, R0, R1); // Result register. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1347 __ mov(R6, Operand(0)); // Zero extend unsigned _state[kSTATE_HI]. | 1347 __ mov(R6, Operand(0)); // Zero extend unsigned _state[kSTATE_HI]. |
| 1348 // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3. | 1348 // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3. |
| 1349 __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2. | 1349 __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2. |
| 1350 __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag); | 1350 __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag); |
| 1351 __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag); | 1351 __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag); |
| 1352 __ Ret(); | 1352 __ Ret(); |
| 1353 } | 1353 } |
| 1354 } | 1354 } |
| 1355 | 1355 |
| 1356 | 1356 |
| 1357 void Intrinsifier::Object_equal(Assembler* assembler) { | 1357 void Intrinsifier::ObjectEquals(Assembler* assembler) { |
| 1358 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1358 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1359 __ ldr(R1, Address(SP, 1 * kWordSize)); | 1359 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| 1360 __ cmp(R0, Operand(R1)); | 1360 __ cmp(R0, Operand(R1)); |
| 1361 __ LoadObject(R0, Bool::False(), NE); | 1361 __ LoadObject(R0, Bool::False(), NE); |
| 1362 __ LoadObject(R0, Bool::True(), EQ); | 1362 __ LoadObject(R0, Bool::True(), EQ); |
| 1363 __ Ret(); | 1363 __ Ret(); |
| 1364 } | 1364 } |
| 1365 | 1365 |
| 1366 | 1366 |
| 1367 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1367 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1368 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1368 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1369 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | 1369 __ ldr(R0, FieldAddress(R0, String::hash_offset())); |
| 1370 __ cmp(R0, Operand(0)); | 1370 __ cmp(R0, Operand(0)); |
| 1371 __ bx(LR, NE); // Hash not yet computed. | 1371 __ bx(LR, NE); // Hash not yet computed. |
| 1372 } | 1372 } |
| 1373 | 1373 |
| 1374 | 1374 |
| 1375 void Intrinsifier::String_getLength(Assembler* assembler) { | 1375 void Intrinsifier::StringBaseLength(Assembler* assembler) { |
| 1376 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1376 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1377 __ ldr(R0, FieldAddress(R0, String::length_offset())); | 1377 __ ldr(R0, FieldAddress(R0, String::length_offset())); |
| 1378 __ Ret(); | 1378 __ Ret(); |
| 1379 } | 1379 } |
| 1380 | 1380 |
| 1381 | 1381 |
| 1382 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1382 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { |
| 1383 Label fall_through, try_two_byte_string; | 1383 Label fall_through, try_two_byte_string; |
| 1384 | 1384 |
| 1385 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1385 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1386 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1386 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1387 __ tst(R1, Operand(kSmiTagMask)); | 1387 __ tst(R1, Operand(kSmiTagMask)); |
| 1388 __ b(&fall_through, NE); // Index is not a Smi. | 1388 __ b(&fall_through, NE); // Index is not a Smi. |
| 1389 // Range check. | 1389 // Range check. |
| 1390 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1390 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1391 __ cmp(R1, Operand(R2)); | 1391 __ cmp(R1, Operand(R2)); |
| 1392 __ b(&fall_through, CS); // Runtime throws exception. | 1392 __ b(&fall_through, CS); // Runtime throws exception. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1404 ASSERT(kSmiTagShift == 1); | 1404 ASSERT(kSmiTagShift == 1); |
| 1405 __ AddImmediate(R0, TwoByteString::data_offset() - kHeapObjectTag); | 1405 __ AddImmediate(R0, TwoByteString::data_offset() - kHeapObjectTag); |
| 1406 __ ldrh(R0, Address(R0, R1)); | 1406 __ ldrh(R0, Address(R0, R1)); |
| 1407 __ SmiTag(R0); | 1407 __ SmiTag(R0); |
| 1408 __ Ret(); | 1408 __ Ret(); |
| 1409 | 1409 |
| 1410 __ Bind(&fall_through); | 1410 __ Bind(&fall_through); |
| 1411 } | 1411 } |
| 1412 | 1412 |
| 1413 | 1413 |
| 1414 void Intrinsifier::String_getIsEmpty(Assembler* assembler) { | 1414 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
| 1415 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1415 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1416 __ ldr(R0, FieldAddress(R0, String::length_offset())); | 1416 __ ldr(R0, FieldAddress(R0, String::length_offset())); |
| 1417 __ cmp(R0, Operand(Smi::RawValue(0))); | 1417 __ cmp(R0, Operand(Smi::RawValue(0))); |
| 1418 __ LoadObject(R0, Bool::True(), EQ); | 1418 __ LoadObject(R0, Bool::True(), EQ); |
| 1419 __ LoadObject(R0, Bool::False(), NE); | 1419 __ LoadObject(R0, Bool::False(), NE); |
| 1420 __ Ret(); | 1420 __ Ret(); |
| 1421 } | 1421 } |
| 1422 | 1422 |
| 1423 | 1423 |
| 1424 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1424 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1609 __ strb(R1, FieldAddress(R7, OneByteString::data_offset())); | 1609 __ strb(R1, FieldAddress(R7, OneByteString::data_offset())); |
| 1610 __ AddImmediate(R7, 1); | 1610 __ AddImmediate(R7, 1); |
| 1611 __ b(&loop, GT); | 1611 __ b(&loop, GT); |
| 1612 | 1612 |
| 1613 __ Bind(&done); | 1613 __ Bind(&done); |
| 1614 __ Ret(); | 1614 __ Ret(); |
| 1615 __ Bind(&fall_through); | 1615 __ Bind(&fall_through); |
| 1616 } | 1616 } |
| 1617 | 1617 |
| 1618 | 1618 |
| 1619 void Intrinsifier::OneByteString_setAt(Assembler* assembler) { | 1619 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { |
| 1620 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 1620 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 1621 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 1621 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 1622 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString. | 1622 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString. |
| 1623 __ SmiUntag(R1); | 1623 __ SmiUntag(R1); |
| 1624 __ SmiUntag(R2); | 1624 __ SmiUntag(R2); |
| 1625 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag); | 1625 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag); |
| 1626 __ strb(R2, Address(R3, R1)); | 1626 __ strb(R2, Address(R3, R1)); |
| 1627 __ Ret(); | 1627 __ Ret(); |
| 1628 } | 1628 } |
| 1629 | 1629 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1749 Isolate* isolate = Isolate::Current(); | 1749 Isolate* isolate = Isolate::Current(); |
| 1750 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate)); | 1750 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate)); |
| 1751 // Set return value to Isolate::current_tag_. | 1751 // Set return value to Isolate::current_tag_. |
| 1752 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); | 1752 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); |
| 1753 __ Ret(); | 1753 __ Ret(); |
| 1754 } | 1754 } |
| 1755 | 1755 |
| 1756 } // namespace dart | 1756 } // namespace dart |
| 1757 | 1757 |
| 1758 #endif // defined TARGET_ARCH_ARM | 1758 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |