| 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::ObjectArrayLength(Assembler* assembler) { | 25 intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; } |
| 26 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 27 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | |
| 28 __ Ret(); | |
| 29 } | |
| 30 | |
| 31 | |
| 32 void Intrinsifier::ImmutableArrayLength(Assembler* assembler) { | |
| 33 ObjectArrayLength(assembler); | |
| 34 } | |
| 35 | |
| 36 | |
| 37 void Intrinsifier::ObjectArrayGetIndexed(Assembler* assembler) { | |
| 38 Label fall_through; | |
| 39 | |
| 40 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | |
| 41 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | |
| 42 | |
| 43 __ tst(R0, Operand(kSmiTagMask)); | |
| 44 __ b(&fall_through, NE); // Index is not an smi, fall through | |
| 45 | |
| 46 // Range check. | |
| 47 __ ldr(R6, FieldAddress(R1, Array::length_offset())); | |
| 48 __ cmp(R0, Operand(R6)); | |
| 49 | |
| 50 ASSERT(kSmiTagShift == 1); | |
| 51 // array element at R1 + R0*2 + Array::data_offset - 1 | |
| 52 __ add(R6, R1, Operand(R0, LSL, 1), CC); | |
| 53 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); | |
| 54 __ bx(LR, CC); | |
| 55 __ Bind(&fall_through); | |
| 56 } | |
| 57 | |
| 58 | |
| 59 void Intrinsifier::ImmutableArrayGetIndexed(Assembler* assembler) { | |
| 60 ObjectArrayGetIndexed(assembler); | |
| 61 } | |
| 62 | 26 |
| 63 | 27 |
| 64 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 28 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 65 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 29 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 66 const Class& cls = Class::Handle( | 30 const Class& cls = Class::Handle( |
| 67 core_lib.LookupClassAllowPrivate(Symbols::_List())); | 31 core_lib.LookupClassAllowPrivate(Symbols::_List())); |
| 68 ASSERT(!cls.IsNull()); | 32 ASSERT(!cls.IsNull()); |
| 69 ASSERT(cls.NumTypeArguments() == 1); | 33 ASSERT(cls.NumTypeArguments() == 1); |
| 70 const intptr_t field_offset = cls.type_arguments_field_offset(); | 34 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 71 ASSERT(field_offset != Class::kNoTypeArguments); | 35 ASSERT(field_offset != Class::kNoTypeArguments); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 | 130 |
| 167 // Set the length field in the growable array object to 0. | 131 // Set the length field in the growable array object to 0. |
| 168 __ LoadImmediate(R1, 0); | 132 __ LoadImmediate(R1, 0); |
| 169 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 133 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 170 __ Ret(); // Returns the newly allocated object in R0. | 134 __ Ret(); // Returns the newly allocated object in R0. |
| 171 | 135 |
| 172 __ Bind(&fall_through); | 136 __ Bind(&fall_through); |
| 173 } | 137 } |
| 174 | 138 |
| 175 | 139 |
| 176 void Intrinsifier::GrowableArrayLength(Assembler* assembler) { | |
| 177 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 178 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); | |
| 179 __ Ret(); | |
| 180 } | |
| 181 | |
| 182 | |
| 183 void Intrinsifier::GrowableArrayCapacity(Assembler* assembler) { | |
| 184 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 185 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); | |
| 186 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | |
| 187 __ Ret(); | |
| 188 } | |
| 189 | |
| 190 | |
| 191 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { | 140 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { |
| 192 Label fall_through; | 141 Label fall_through; |
| 193 | 142 |
| 194 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 143 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 195 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 144 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 196 | 145 |
| 197 __ tst(R0, Operand(kSmiTagMask)); | 146 __ tst(R0, Operand(kSmiTagMask)); |
| 198 __ b(&fall_through, NE); // Index is not an smi, fall through | 147 __ b(&fall_through, NE); // Index is not an smi, fall through |
| 199 | 148 |
| 200 // Range check. | 149 // Range check. |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 __ Bind(&init_loop); \ | 334 __ Bind(&init_loop); \ |
| 386 __ cmp(R2, Operand(R1)); \ | 335 __ cmp(R2, Operand(R1)); \ |
| 387 __ str(R3, Address(R2, 0), CC); \ | 336 __ str(R3, Address(R2, 0), CC); \ |
| 388 __ add(R2, R2, Operand(kWordSize), CC); \ | 337 __ add(R2, R2, Operand(kWordSize), CC); \ |
| 389 __ b(&init_loop, CC); \ | 338 __ b(&init_loop, CC); \ |
| 390 \ | 339 \ |
| 391 __ Ret(); \ | 340 __ Ret(); \ |
| 392 __ Bind(&fall_through); \ | 341 __ Bind(&fall_through); \ |
| 393 | 342 |
| 394 | 343 |
| 395 // Gets the length of a TypedData. | |
| 396 void Intrinsifier::TypedDataLength(Assembler* assembler) { | |
| 397 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 398 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); | |
| 399 __ Ret(); | |
| 400 } | |
| 401 | |
| 402 | |
| 403 void Intrinsifier::Uint8ArrayGetIndexed(Assembler* assembler) { | |
| 404 Label fall_through; | |
| 405 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | |
| 406 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | |
| 407 __ tst(R0, Operand(kSmiTagMask)); | |
| 408 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 409 | |
| 410 // Range check. | |
| 411 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 412 __ cmp(R0, Operand(R6)); | |
| 413 __ b(&fall_through, CS); | |
| 414 | |
| 415 __ SmiUntag(R0); | |
| 416 __ AddImmediate(R1, TypedData::data_offset() - kHeapObjectTag); | |
| 417 __ ldrb(R0, Address(R1, R0)); | |
| 418 __ SmiTag(R0); | |
| 419 __ Ret(); | |
| 420 __ Bind(&fall_through); | |
| 421 } | |
| 422 | |
| 423 | |
| 424 void Intrinsifier::ExternalUint8ArrayGetIndexed(Assembler* assembler) { | |
| 425 Label fall_through; | |
| 426 | |
| 427 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | |
| 428 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | |
| 429 __ tst(R0, Operand(kSmiTagMask)); | |
| 430 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 431 | |
| 432 // Range check. | |
| 433 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 434 __ cmp(R0, Operand(R6)); | |
| 435 __ b(&fall_through, CS); | |
| 436 | |
| 437 __ LoadFromOffset(kWord, R1, R1, | |
| 438 ExternalTypedData::data_offset() - kHeapObjectTag); | |
| 439 __ SmiUntag(R0); | |
| 440 __ ldrb(R0, Address(R1, R0)); | |
| 441 __ SmiTag(R0); | |
| 442 __ Ret(); | |
| 443 __ Bind(&fall_through); | |
| 444 } | |
| 445 | |
| 446 | |
| 447 void Intrinsifier::Float64ArrayGetIndexed(Assembler* assembler) { | |
| 448 if (!TargetCPUFeatures::vfp_supported()) { | |
| 449 return; | |
| 450 } | |
| 451 Label fall_through; | |
| 452 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | |
| 453 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | |
| 454 __ tst(R0, Operand(kSmiTagMask)); | |
| 455 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 456 | |
| 457 // Range check. | |
| 458 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 459 __ cmp(R0, Operand(R6)); | |
| 460 __ b(&fall_through, CS); | |
| 461 | |
| 462 | |
| 463 Address element_address = | |
| 464 __ ElementAddressForRegIndex(true, // Load. | |
| 465 false, // Not external. | |
| 466 kTypedDataFloat64ArrayCid, // Cid. | |
| 467 8, // Index scale. | |
| 468 R1, // Array. | |
| 469 R0); // Index. | |
| 470 | |
| 471 __ vldrd(D0, element_address); | |
| 472 | |
| 473 const Class& double_class = Class::Handle( | |
| 474 Isolate::Current()->object_store()->double_class()); | |
| 475 __ TryAllocate(double_class, | |
| 476 &fall_through, | |
| 477 R0, // Result register. | |
| 478 R1); | |
| 479 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | |
| 480 __ Ret(); | |
| 481 __ Bind(&fall_through); | |
| 482 } | |
| 483 | |
| 484 | |
| 485 void Intrinsifier::Float64ArraySetIndexed(Assembler* assembler) { | |
| 486 if (!TargetCPUFeatures::vfp_supported()) { | |
| 487 return; | |
| 488 } | |
| 489 Label fall_through; | |
| 490 __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index. | |
| 491 __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array. | |
| 492 __ tst(R0, Operand(kSmiTagMask)); | |
| 493 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 494 | |
| 495 // Range check. | |
| 496 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 497 __ cmp(R0, Operand(R6)); | |
| 498 __ b(&fall_through, CS); | |
| 499 | |
| 500 __ ldr(R2, Address(SP, + 0 * kWordSize)); // Value. | |
| 501 __ tst(R2, Operand(kSmiTagMask)); | |
| 502 __ b(&fall_through, EQ); // Value is Smi, fall through. | |
| 503 | |
| 504 __ LoadClassId(R3, R2); | |
| 505 __ CompareImmediate(R3, kDoubleCid); | |
| 506 __ b(&fall_through, NE); // Not a Double, fall through. | |
| 507 | |
| 508 __ LoadDFromOffset(D0, R2, Double::value_offset() - kHeapObjectTag); | |
| 509 | |
| 510 Address element_address = | |
| 511 __ ElementAddressForRegIndex(false, // Store. | |
| 512 false, // Not external. | |
| 513 kTypedDataFloat64ArrayCid, // Cid. | |
| 514 8, // Index scale. | |
| 515 R1, // Array. | |
| 516 R0); // Index. | |
| 517 __ vstrd(D0, element_address); | |
| 518 __ Ret(); | |
| 519 __ Bind(&fall_through); | |
| 520 } | |
| 521 | |
| 522 | |
| 523 static int GetScaleFactor(intptr_t size) { | 344 static int GetScaleFactor(intptr_t size) { |
| 524 switch (size) { | 345 switch (size) { |
| 525 case 1: return 0; | 346 case 1: return 0; |
| 526 case 2: return 1; | 347 case 2: return 1; |
| 527 case 4: return 2; | 348 case 4: return 2; |
| 528 case 8: return 3; | 349 case 8: return 3; |
| 529 case 16: return 4; | 350 case 16: return 4; |
| 530 } | 351 } |
| 531 UNREACHABLE(); | 352 UNREACHABLE(); |
| 532 return -1; | 353 return -1; |
| (...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 | 1186 |
| 1366 | 1187 |
| 1367 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1188 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1368 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1189 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1369 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | 1190 __ ldr(R0, FieldAddress(R0, String::hash_offset())); |
| 1370 __ cmp(R0, Operand(0)); | 1191 __ cmp(R0, Operand(0)); |
| 1371 __ bx(LR, NE); // Hash not yet computed. | 1192 __ bx(LR, NE); // Hash not yet computed. |
| 1372 } | 1193 } |
| 1373 | 1194 |
| 1374 | 1195 |
| 1375 void Intrinsifier::StringBaseLength(Assembler* assembler) { | |
| 1376 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 1377 __ ldr(R0, FieldAddress(R0, String::length_offset())); | |
| 1378 __ Ret(); | |
| 1379 } | |
| 1380 | |
| 1381 | |
| 1382 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { | 1196 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { |
| 1383 Label fall_through, try_two_byte_string; | 1197 Label fall_through, try_two_byte_string; |
| 1384 | 1198 |
| 1385 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1199 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1386 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1200 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1387 __ tst(R1, Operand(kSmiTagMask)); | 1201 __ tst(R1, Operand(kSmiTagMask)); |
| 1388 __ b(&fall_through, NE); // Index is not a Smi. | 1202 __ b(&fall_through, NE); // Index is not a Smi. |
| 1389 // Range check. | 1203 // Range check. |
| 1390 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1204 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1391 __ cmp(R1, Operand(R2)); | 1205 __ cmp(R1, Operand(R2)); |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1792 Isolate* isolate = Isolate::Current(); | 1606 Isolate* isolate = Isolate::Current(); |
| 1793 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate)); | 1607 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate)); |
| 1794 // Set return value to Isolate::current_tag_. | 1608 // Set return value to Isolate::current_tag_. |
| 1795 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); | 1609 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); |
| 1796 __ Ret(); | 1610 __ Ret(); |
| 1797 } | 1611 } |
| 1798 | 1612 |
| 1799 } // namespace dart | 1613 } // namespace dart |
| 1800 | 1614 |
| 1801 #endif // defined TARGET_ARCH_ARM | 1615 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |