| 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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 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 __ lw(T3, Address(SP, kArrayLengthOffset)); // Array length. | 31 __ lw(T3, Address(SP, kArrayLengthOffset)); // Array length. |
| 32 | 32 |
| 33 // Check that length is a positive Smi. | 33 // Check that length is a positive Smi. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 } | 133 } |
| 134 | 134 |
| 135 | 135 |
| 136 void Intrinsifier::Array_getLength(Assembler* assembler) { | 136 void Intrinsifier::Array_getLength(Assembler* assembler) { |
| 137 __ lw(V0, Address(SP, 0 * kWordSize)); | 137 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 138 __ Ret(); | 138 __ Ret(); |
| 139 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); | 139 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); |
| 140 } | 140 } |
| 141 | 141 |
| 142 | 142 |
| 143 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { | 143 void Intrinsifier::ImmutableList_getLength(Assembler* assembler) { |
| 144 return Array_getLength(assembler); | 144 return Array_getLength(assembler); |
| 145 } | 145 } |
| 146 | 146 |
| 147 | 147 |
| 148 void Intrinsifier::Array_getIndexed(Assembler* assembler) { | 148 void Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 149 Label fall_through; | 149 Label fall_through; |
| 150 | 150 |
| 151 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index | 151 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index |
| 152 | 152 |
| 153 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 153 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 154 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through | 154 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through |
| 155 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array | 155 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array |
| 156 | 156 |
| 157 // range check | 157 // range check |
| 158 __ lw(T2, FieldAddress(T1, Array::length_offset())); | 158 __ lw(T2, FieldAddress(T1, Array::length_offset())); |
| 159 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 159 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 160 | 160 |
| 161 ASSERT(kSmiTagShift == 1); | 161 ASSERT(kSmiTagShift == 1); |
| 162 // array element at T1 + T0*2 + Array::data_offset - 1 | 162 // array element at T1 + T0*2 + Array::data_offset - 1 |
| 163 __ sll(T2, T0, 1); | 163 __ sll(T2, T0, 1); |
| 164 __ addu(T2, T1, T2); | 164 __ addu(T2, T1, T2); |
| 165 __ Ret(); | 165 __ Ret(); |
| 166 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); | 166 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); |
| 167 __ Bind(&fall_through); | 167 __ Bind(&fall_through); |
| 168 } | 168 } |
| 169 | 169 |
| 170 | 170 |
| 171 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { | 171 void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) { |
| 172 return Array_getIndexed(assembler); | 172 return Array_getIndexed(assembler); |
| 173 } | 173 } |
| 174 | 174 |
| 175 | 175 |
| 176 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 176 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 177 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 177 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 178 const Class& cls = Class::Handle( | 178 const Class& cls = Class::Handle( |
| 179 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray())); | 179 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray())); |
| 180 ASSERT(!cls.IsNull()); | 180 ASSERT(!cls.IsNull()); |
| 181 ASSERT(cls.HasTypeArguments()); | 181 ASSERT(cls.HasTypeArguments()); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 FieldAddress(T1, Array::data_offset()), | 245 FieldAddress(T1, Array::data_offset()), |
| 246 T2); | 246 T2); |
| 247 // Caller is responsible for preserving the value if necessary. | 247 // Caller is responsible for preserving the value if necessary. |
| 248 __ Ret(); | 248 __ Ret(); |
| 249 __ Bind(&fall_through); | 249 __ Bind(&fall_through); |
| 250 } | 250 } |
| 251 | 251 |
| 252 | 252 |
| 253 // Allocate a GrowableObjectArray using the backing array specified. | 253 // Allocate a GrowableObjectArray using the backing array specified. |
| 254 // On stack: type argument (+1), data (+0). | 254 // On stack: type argument (+1), data (+0). |
| 255 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 255 void Intrinsifier::GrowableList_Allocate(Assembler* assembler) { |
| 256 // The newly allocated object is returned in V0. | 256 // The newly allocated object is returned in V0. |
| 257 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 257 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 258 const intptr_t kArrayOffset = 0 * kWordSize; | 258 const intptr_t kArrayOffset = 0 * kWordSize; |
| 259 Label fall_through; | 259 Label fall_through; |
| 260 | 260 |
| 261 // Compute the size to be allocated, it is based on the array length | 261 // Compute the size to be allocated, it is based on the array length |
| 262 // and is computed as: | 262 // and is computed as: |
| 263 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 263 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| 264 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); | 264 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); |
| 265 | 265 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 | 310 |
| 311 // Set the length field in the growable array object to 0. | 311 // Set the length field in the growable array object to 0. |
| 312 __ Ret(); // Returns the newly allocated object in V0. | 312 __ Ret(); // Returns the newly allocated object in V0. |
| 313 __ delay_slot()->sw(ZR, | 313 __ delay_slot()->sw(ZR, |
| 314 FieldAddress(V0, GrowableObjectArray::length_offset())); | 314 FieldAddress(V0, GrowableObjectArray::length_offset())); |
| 315 | 315 |
| 316 __ Bind(&fall_through); | 316 __ Bind(&fall_through); |
| 317 } | 317 } |
| 318 | 318 |
| 319 | 319 |
| 320 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 320 void Intrinsifier::GrowableList_getLength(Assembler* assembler) { |
| 321 __ lw(V0, Address(SP, 0 * kWordSize)); | 321 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 322 __ Ret(); | 322 __ Ret(); |
| 323 __ delay_slot()->lw(V0, | 323 __ delay_slot()->lw(V0, |
| 324 FieldAddress(V0, GrowableObjectArray::length_offset())); | 324 FieldAddress(V0, GrowableObjectArray::length_offset())); |
| 325 } | 325 } |
| 326 | 326 |
| 327 | 327 |
| 328 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 328 void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) { |
| 329 __ lw(V0, Address(SP, 0 * kWordSize)); | 329 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 330 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset())); | 330 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset())); |
| 331 __ Ret(); | 331 __ Ret(); |
| 332 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); | 332 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); |
| 333 } | 333 } |
| 334 | 334 |
| 335 | 335 |
| 336 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 336 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { |
| 337 Label fall_through; | 337 Label fall_through; |
| 338 | 338 |
| 339 __ lw(T0, Address(SP, 0 * kWordSize)); // Index | 339 __ lw(T0, Address(SP, 0 * kWordSize)); // Index |
| 340 | 340 |
| 341 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 341 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 342 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through | 342 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through |
| 343 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array | 343 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array |
| 344 | 344 |
| 345 // range check | 345 // range check |
| 346 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); | 346 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); |
| 347 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 347 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 348 | 348 |
| 349 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data | 349 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data |
| 350 | 350 |
| 351 ASSERT(kSmiTagShift == 1); | 351 ASSERT(kSmiTagShift == 1); |
| 352 // array element at T2 + T0 * 2 + Array::data_offset - 1 | 352 // array element at T2 + T0 * 2 + Array::data_offset - 1 |
| 353 __ sll(T3, T0, 1); | 353 __ sll(T3, T0, 1); |
| 354 __ addu(T2, T2, T3); | 354 __ addu(T2, T2, T3); |
| 355 __ Ret(); | 355 __ Ret(); |
| 356 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); | 356 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); |
| 357 __ Bind(&fall_through); | 357 __ Bind(&fall_through); |
| 358 } | 358 } |
| 359 | 359 |
| 360 | 360 |
| 361 // Set value into growable object array at specified index. | 361 // Set value into growable object array at specified index. |
| 362 // On stack: growable array (+2), index (+1), value (+0). | 362 // On stack: growable array (+2), index (+1), value (+0). |
| 363 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 363 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { |
| 364 if (FLAG_enable_type_checks) { | 364 if (FLAG_enable_type_checks) { |
| 365 return; | 365 return; |
| 366 } | 366 } |
| 367 Label fall_through; | 367 Label fall_through; |
| 368 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. | 368 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. |
| 369 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 369 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); |
| 370 __ bne(CMPRES, ZR, &fall_through); // Non-smi index. | 370 __ bne(CMPRES, ZR, &fall_through); // Non-smi index. |
| 371 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. | 371 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 372 // Range check using _length field. | 372 // Range check using _length field. |
| 373 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); | 373 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 374 // Runtime throws exception. | 374 // Runtime throws exception. |
| 375 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); | 375 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); |
| 376 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. | 376 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. |
| 377 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 377 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 378 // Note that T1 is Smi, i.e, times 2. | 378 // Note that T1 is Smi, i.e, times 2. |
| 379 ASSERT(kSmiTagShift == 1); | 379 ASSERT(kSmiTagShift == 1); |
| 380 __ sll(T1, T1, 1); | 380 __ sll(T1, T1, 1); |
| 381 __ addu(T1, T0, T1); | 381 __ addu(T1, T0, T1); |
| 382 __ StoreIntoObject(T0, | 382 __ StoreIntoObject(T0, |
| 383 FieldAddress(T1, Array::data_offset()), | 383 FieldAddress(T1, Array::data_offset()), |
| 384 T2); | 384 T2); |
| 385 __ Ret(); | 385 __ Ret(); |
| 386 __ Bind(&fall_through); | 386 __ Bind(&fall_through); |
| 387 } | 387 } |
| 388 | 388 |
| 389 | 389 |
| 390 // Set length of growable object array. The length cannot | 390 // Set length of growable object array. The length cannot |
| 391 // be greater than the length of the data container. | 391 // be greater than the length of the data container. |
| 392 // On stack: growable array (+1), length (+0). | 392 // On stack: growable array (+1), length (+0). |
| 393 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 393 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { |
| 394 Label fall_through; | 394 Label fall_through; |
| 395 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. | 395 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. |
| 396 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 396 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); |
| 397 __ bne(CMPRES, ZR, &fall_through); // Non-smi length. | 397 __ bne(CMPRES, ZR, &fall_through); // Non-smi length. |
| 398 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 398 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 399 __ Ret(); | 399 __ Ret(); |
| 400 __ delay_slot()->sw(T1, | 400 __ delay_slot()->sw(T1, |
| 401 FieldAddress(T0, GrowableObjectArray::length_offset())); | 401 FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 402 __ Bind(&fall_through); | 402 __ Bind(&fall_through); |
| 403 } | 403 } |
| 404 | 404 |
| 405 | 405 |
| 406 // Set data of growable object array. | 406 // Set data of growable object array. |
| 407 // On stack: growable array (+1), data (+0). | 407 // On stack: growable array (+1), data (+0). |
| 408 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 408 void Intrinsifier::GrowableList_setData(Assembler* assembler) { |
| 409 if (FLAG_enable_type_checks) { | 409 if (FLAG_enable_type_checks) { |
| 410 return; | 410 return; |
| 411 } | 411 } |
| 412 Label fall_through; | 412 Label fall_through; |
| 413 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. | 413 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. |
| 414 // Check that data is an ObjectArray. | 414 // Check that data is an ObjectArray. |
| 415 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 415 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); |
| 416 __ beq(CMPRES, ZR, &fall_through); // Data is Smi. | 416 __ beq(CMPRES, ZR, &fall_through); // Data is Smi. |
| 417 __ LoadClassId(CMPRES1, T1); | 417 __ LoadClassId(CMPRES1, T1); |
| 418 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); | 418 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); |
| 419 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 419 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 420 __ StoreIntoObject(T0, | 420 __ StoreIntoObject(T0, |
| 421 FieldAddress(T0, GrowableObjectArray::data_offset()), | 421 FieldAddress(T0, GrowableObjectArray::data_offset()), |
| 422 T1); | 422 T1); |
| 423 __ Ret(); | 423 __ Ret(); |
| 424 __ Bind(&fall_through); | 424 __ Bind(&fall_through); |
| 425 } | 425 } |
| 426 | 426 |
| 427 | 427 |
| 428 // Add an element to growable array if it doesn't need to grow, otherwise | 428 // Add an element to growable array if it doesn't need to grow, otherwise |
| 429 // call into regular code. | 429 // call into regular code. |
| 430 // On stack: growable array (+1), value (+0). | 430 // On stack: growable array (+1), value (+0). |
| 431 void Intrinsifier::GrowableArray_add(Assembler* assembler) { | 431 void Intrinsifier::GrowableList_add(Assembler* assembler) { |
| 432 // In checked mode we need to type-check the incoming argument. | 432 // In checked mode we need to type-check the incoming argument. |
| 433 if (FLAG_enable_type_checks) return; | 433 if (FLAG_enable_type_checks) return; |
| 434 Label fall_through; | 434 Label fall_through; |
| 435 __ lw(T0, Address(SP, 1 * kWordSize)); // Array. | 435 __ lw(T0, Address(SP, 1 * kWordSize)); // Array. |
| 436 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset())); | 436 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 437 // T1: length. | 437 // T1: length. |
| 438 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset())); | 438 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset())); |
| 439 // T2: data. | 439 // T2: data. |
| 440 __ lw(T3, FieldAddress(T2, Array::length_offset())); | 440 __ lw(T3, FieldAddress(T2, Array::length_offset())); |
| 441 // Compare length with capacity. | 441 // Compare length with capacity. |
| (...skipping 1292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1734 | 1734 |
| 1735 __ Bind(&ok); | 1735 __ Bind(&ok); |
| 1736 __ Ret(); | 1736 __ Ret(); |
| 1737 | 1737 |
| 1738 __ Bind(&fall_through); | 1738 __ Bind(&fall_through); |
| 1739 } | 1739 } |
| 1740 | 1740 |
| 1741 } // namespace dart | 1741 } // namespace dart |
| 1742 | 1742 |
| 1743 #endif // defined TARGET_ARCH_MIPS | 1743 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |