| 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/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 #include "vm/symbols.h" | 14 #include "vm/symbols.h" |
| 15 | 15 |
| 16 namespace dart { | 16 namespace dart { |
| 17 | 17 |
| 18 DECLARE_FLAG(bool, enable_type_checks); | 18 DECLARE_FLAG(bool, enable_type_checks); |
| 19 | 19 |
| 20 | 20 |
| 21 #define __ assembler-> | 21 #define __ assembler-> |
| 22 | 22 |
| 23 void Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { | 23 void Intrinsifier::List_Allocate(Assembler* assembler) { |
| 24 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 24 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 25 const intptr_t kArrayLengthOffset = 0 * kWordSize; | 25 const intptr_t kArrayLengthOffset = 0 * kWordSize; |
| 26 Label fall_through; | 26 Label fall_through; |
| 27 | 27 |
| 28 // Compute the size to be allocated, it is based on the array length | 28 // Compute the size to be allocated, it is based on the array length |
| 29 // and is computed as: | 29 // and is computed as: |
| 30 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 30 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 31 __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length. | 31 __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length. |
| 32 | 32 |
| 33 // Check that length is a positive Smi. | 33 // Check that length is a positive Smi. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 } | 126 } |
| 127 | 127 |
| 128 | 128 |
| 129 void Intrinsifier::Array_getLength(Assembler* assembler) { | 129 void Intrinsifier::Array_getLength(Assembler* assembler) { |
| 130 __ ldr(R0, Address(SP, 0 * kWordSize)); | 130 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 131 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 131 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 132 __ Ret(); | 132 __ Ret(); |
| 133 } | 133 } |
| 134 | 134 |
| 135 | 135 |
| 136 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { | 136 void Intrinsifier::ImmutableList_getLength(Assembler* assembler) { |
| 137 return Array_getLength(assembler); | 137 return Array_getLength(assembler); |
| 138 } | 138 } |
| 139 | 139 |
| 140 | 140 |
| 141 void Intrinsifier::Array_getIndexed(Assembler* assembler) { | 141 void Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 142 Label fall_through; | 142 Label fall_through; |
| 143 | 143 |
| 144 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 144 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 145 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 145 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 146 | 146 |
| 147 __ tst(R0, ShifterOperand(kSmiTagMask)); | 147 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 148 __ b(&fall_through, NE); // Index is not an smi, fall through | 148 __ b(&fall_through, NE); // Index is not an smi, fall through |
| 149 | 149 |
| 150 // range check | 150 // range check |
| 151 __ ldr(R6, FieldAddress(R1, Array::length_offset())); | 151 __ ldr(R6, FieldAddress(R1, Array::length_offset())); |
| 152 __ cmp(R0, ShifterOperand(R6)); | 152 __ cmp(R0, ShifterOperand(R6)); |
| 153 | 153 |
| 154 ASSERT(kSmiTagShift == 1); | 154 ASSERT(kSmiTagShift == 1); |
| 155 // array element at R1 + R0*2 + Array::data_offset - 1 | 155 // array element at R1 + R0*2 + Array::data_offset - 1 |
| 156 __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC); | 156 __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC); |
| 157 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); | 157 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); |
| 158 __ bx(LR, CC); | 158 __ bx(LR, CC); |
| 159 __ Bind(&fall_through); | 159 __ Bind(&fall_through); |
| 160 } | 160 } |
| 161 | 161 |
| 162 | 162 |
| 163 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { | 163 void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) { |
| 164 return Array_getIndexed(assembler); | 164 return Array_getIndexed(assembler); |
| 165 } | 165 } |
| 166 | 166 |
| 167 | 167 |
| 168 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 168 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 169 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 169 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 170 const Class& cls = Class::Handle( | 170 const Class& cls = Class::Handle( |
| 171 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray())); | 171 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray())); |
| 172 ASSERT(!cls.IsNull()); | 172 ASSERT(!cls.IsNull()); |
| 173 ASSERT(cls.HasTypeArguments()); | 173 ASSERT(cls.HasTypeArguments()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 FieldAddress(R1, Array::data_offset()), | 240 FieldAddress(R1, Array::data_offset()), |
| 241 R2); | 241 R2); |
| 242 // Caller is responsible for preserving the value if necessary. | 242 // Caller is responsible for preserving the value if necessary. |
| 243 __ Ret(); | 243 __ Ret(); |
| 244 __ Bind(&fall_through); | 244 __ Bind(&fall_through); |
| 245 } | 245 } |
| 246 | 246 |
| 247 | 247 |
| 248 // Allocate a GrowableObjectArray using the backing array specified. | 248 // Allocate a GrowableObjectArray using the backing array specified. |
| 249 // On stack: type argument (+1), data (+0). | 249 // On stack: type argument (+1), data (+0). |
| 250 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 250 void Intrinsifier::GrowableList_Allocate(Assembler* assembler) { |
| 251 // The newly allocated object is returned in R0. | 251 // The newly allocated object is returned in R0. |
| 252 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 252 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 253 const intptr_t kArrayOffset = 0 * kWordSize; | 253 const intptr_t kArrayOffset = 0 * kWordSize; |
| 254 Label fall_through; | 254 Label fall_through; |
| 255 | 255 |
| 256 // Compute the size to be allocated, it is based on the array length | 256 // Compute the size to be allocated, it is based on the array length |
| 257 // and is computed as: | 257 // and is computed as: |
| 258 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 258 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| 259 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); | 259 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); |
| 260 | 260 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 | 306 |
| 307 // Set the length field in the growable array object to 0. | 307 // Set the length field in the growable array object to 0. |
| 308 __ LoadImmediate(R1, 0); | 308 __ LoadImmediate(R1, 0); |
| 309 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 309 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 310 __ Ret(); // Returns the newly allocated object in R0. | 310 __ Ret(); // Returns the newly allocated object in R0. |
| 311 | 311 |
| 312 __ Bind(&fall_through); | 312 __ Bind(&fall_through); |
| 313 } | 313 } |
| 314 | 314 |
| 315 | 315 |
| 316 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 316 void Intrinsifier::GrowableList_getLength(Assembler* assembler) { |
| 317 __ ldr(R0, Address(SP, 0 * kWordSize)); | 317 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 318 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); | 318 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 319 __ Ret(); | 319 __ Ret(); |
| 320 } | 320 } |
| 321 | 321 |
| 322 | 322 |
| 323 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 323 void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) { |
| 324 __ ldr(R0, Address(SP, 0 * kWordSize)); | 324 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 325 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); | 325 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); |
| 326 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 326 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 327 __ Ret(); | 327 __ Ret(); |
| 328 } | 328 } |
| 329 | 329 |
| 330 | 330 |
| 331 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 331 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { |
| 332 Label fall_through; | 332 Label fall_through; |
| 333 | 333 |
| 334 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 334 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 335 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 335 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 336 | 336 |
| 337 __ tst(R0, ShifterOperand(kSmiTagMask)); | 337 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 338 __ b(&fall_through, NE); // Index is not an smi, fall through | 338 __ b(&fall_through, NE); // Index is not an smi, fall through |
| 339 | 339 |
| 340 // range check | 340 // range check |
| 341 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); | 341 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); |
| 342 __ cmp(R0, ShifterOperand(R6)); | 342 __ cmp(R0, ShifterOperand(R6)); |
| 343 | 343 |
| 344 ASSERT(kSmiTagShift == 1); | 344 ASSERT(kSmiTagShift == 1); |
| 345 // array element at R6 + R0 * 2 + Array::data_offset - 1 | 345 // array element at R6 + R0 * 2 + Array::data_offset - 1 |
| 346 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data | 346 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data |
| 347 __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC); | 347 __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC); |
| 348 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); | 348 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); |
| 349 __ bx(LR, CC); | 349 __ bx(LR, CC); |
| 350 __ Bind(&fall_through); | 350 __ Bind(&fall_through); |
| 351 } | 351 } |
| 352 | 352 |
| 353 | 353 |
| 354 // Set value into growable object array at specified index. | 354 // Set value into growable object array at specified index. |
| 355 // On stack: growable array (+2), index (+1), value (+0). | 355 // On stack: growable array (+2), index (+1), value (+0). |
| 356 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 356 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { |
| 357 if (FLAG_enable_type_checks) { | 357 if (FLAG_enable_type_checks) { |
| 358 return; | 358 return; |
| 359 } | 359 } |
| 360 Label fall_through; | 360 Label fall_through; |
| 361 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 361 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 362 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. | 362 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 363 __ tst(R1, ShifterOperand(kSmiTagMask)); | 363 __ tst(R1, ShifterOperand(kSmiTagMask)); |
| 364 __ b(&fall_through, NE); // Non-smi index. | 364 __ b(&fall_through, NE); // Non-smi index. |
| 365 // Range check using _length field. | 365 // Range check using _length field. |
| 366 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); | 366 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 367 __ cmp(R1, ShifterOperand(R2)); | 367 __ cmp(R1, ShifterOperand(R2)); |
| 368 // Runtime throws exception. | 368 // Runtime throws exception. |
| 369 __ b(&fall_through, CS); | 369 __ b(&fall_through, CS); |
| 370 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. | 370 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. |
| 371 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 371 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 372 // Note that R1 is Smi, i.e, times 2. | 372 // Note that R1 is Smi, i.e, times 2. |
| 373 ASSERT(kSmiTagShift == 1); | 373 ASSERT(kSmiTagShift == 1); |
| 374 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); | 374 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); |
| 375 __ StoreIntoObject(R0, | 375 __ StoreIntoObject(R0, |
| 376 FieldAddress(R1, Array::data_offset()), | 376 FieldAddress(R1, Array::data_offset()), |
| 377 R2); | 377 R2); |
| 378 __ Ret(); | 378 __ Ret(); |
| 379 __ Bind(&fall_through); | 379 __ Bind(&fall_through); |
| 380 } | 380 } |
| 381 | 381 |
| 382 | 382 |
| 383 // Set length of growable object array. The length cannot | 383 // Set length of growable object array. The length cannot |
| 384 // be greater than the length of the data container. | 384 // be greater than the length of the data container. |
| 385 // On stack: growable array (+1), length (+0). | 385 // On stack: growable array (+1), length (+0). |
| 386 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 386 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { |
| 387 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 387 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 388 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. | 388 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. |
| 389 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi. | 389 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi. |
| 390 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ); | 390 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ); |
| 391 __ bx(LR, EQ); | 391 __ bx(LR, EQ); |
| 392 // Fall through on non-Smi. | 392 // Fall through on non-Smi. |
| 393 } | 393 } |
| 394 | 394 |
| 395 | 395 |
| 396 // Set data of growable object array. | 396 // Set data of growable object array. |
| 397 // On stack: growable array (+1), data (+0). | 397 // On stack: growable array (+1), data (+0). |
| 398 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 398 void Intrinsifier::GrowableList_setData(Assembler* assembler) { |
| 399 if (FLAG_enable_type_checks) { | 399 if (FLAG_enable_type_checks) { |
| 400 return; | 400 return; |
| 401 } | 401 } |
| 402 Label fall_through; | 402 Label fall_through; |
| 403 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. | 403 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. |
| 404 // Check that data is an ObjectArray. | 404 // Check that data is an ObjectArray. |
| 405 __ tst(R1, ShifterOperand(kSmiTagMask)); | 405 __ tst(R1, ShifterOperand(kSmiTagMask)); |
| 406 __ b(&fall_through, EQ); // Data is Smi. | 406 __ b(&fall_through, EQ); // Data is Smi. |
| 407 __ CompareClassId(R1, kArrayCid, R0); | 407 __ CompareClassId(R1, kArrayCid, R0); |
| 408 __ b(&fall_through, NE); | 408 __ b(&fall_through, NE); |
| 409 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 409 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 410 __ StoreIntoObject(R0, | 410 __ StoreIntoObject(R0, |
| 411 FieldAddress(R0, GrowableObjectArray::data_offset()), | 411 FieldAddress(R0, GrowableObjectArray::data_offset()), |
| 412 R1); | 412 R1); |
| 413 __ Ret(); | 413 __ Ret(); |
| 414 __ Bind(&fall_through); | 414 __ Bind(&fall_through); |
| 415 } | 415 } |
| 416 | 416 |
| 417 | 417 |
| 418 // Add an element to growable array if it doesn't need to grow, otherwise | 418 // Add an element to growable array if it doesn't need to grow, otherwise |
| 419 // call into regular code. | 419 // call into regular code. |
| 420 // On stack: growable array (+1), value (+0). | 420 // On stack: growable array (+1), value (+0). |
| 421 void Intrinsifier::GrowableArray_add(Assembler* assembler) { | 421 void Intrinsifier::GrowableList_add(Assembler* assembler) { |
| 422 // In checked mode we need to type-check the incoming argument. | 422 // In checked mode we need to type-check the incoming argument. |
| 423 if (FLAG_enable_type_checks) return; | 423 if (FLAG_enable_type_checks) return; |
| 424 Label fall_through; | 424 Label fall_through; |
| 425 // R0: Array. | 425 // R0: Array. |
| 426 __ ldr(R0, Address(SP, 1 * kWordSize)); | 426 __ ldr(R0, Address(SP, 1 * kWordSize)); |
| 427 // R1: length. | 427 // R1: length. |
| 428 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 428 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 429 // R2: data. | 429 // R2: data. |
| 430 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset())); | 430 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset())); |
| 431 // R3: capacity. | 431 // R3: capacity. |
| (...skipping 1219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1651 | 1651 |
| 1652 __ Bind(&ok); | 1652 __ Bind(&ok); |
| 1653 __ Ret(); | 1653 __ Ret(); |
| 1654 | 1654 |
| 1655 __ Bind(&fall_through); | 1655 __ Bind(&fall_through); |
| 1656 } | 1656 } |
| 1657 | 1657 |
| 1658 } // namespace dart | 1658 } // namespace dart |
| 1659 | 1659 |
| 1660 #endif // defined TARGET_ARCH_ARM | 1660 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |