| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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 | 23 |
| 24 void Intrinsifier::ObjectArrayLength(Assembler* assembler) { | 24 intptr_t Intrinsifier::ParameterSlotFromSp() { return -1; } |
| 25 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 26 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | |
| 27 __ ret(); | |
| 28 } | |
| 29 | |
| 30 | |
| 31 void Intrinsifier::ImmutableArrayLength(Assembler* assembler) { | |
| 32 ObjectArrayLength(assembler); | |
| 33 } | |
| 34 | |
| 35 | |
| 36 void Intrinsifier::ObjectArrayGetIndexed(Assembler* assembler) { | |
| 37 Label fall_through; | |
| 38 | |
| 39 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | |
| 40 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | |
| 41 | |
| 42 __ tsti(R0, kSmiTagMask); | |
| 43 __ b(&fall_through, NE); // Index is not an smi, fall through. | |
| 44 | |
| 45 // Range check. | |
| 46 __ ldr(R6, FieldAddress(R1, Array::length_offset())); | |
| 47 __ cmp(R0, Operand(R6)); | |
| 48 __ b(&fall_through, CS); | |
| 49 | |
| 50 ASSERT(kSmiTagShift == 1); | |
| 51 // array element at R1 + R0*4 + Array::data_offset - 1 | |
| 52 __ add(R6, R1, Operand(R0, LSL, 2)); | |
| 53 __ ldr(R0, FieldAddress(R6, Array::data_offset())); | |
| 54 __ ret(); | |
| 55 __ Bind(&fall_through); | |
| 56 } | |
| 57 | |
| 58 | |
| 59 void Intrinsifier::ImmutableArrayGetIndexed(Assembler* assembler) { | |
| 60 ObjectArrayGetIndexed(assembler); | |
| 61 } | |
| 62 | 25 |
| 63 | 26 |
| 64 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 27 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 65 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 28 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 66 const Class& cls = Class::Handle( | 29 const Class& cls = Class::Handle( |
| 67 core_lib.LookupClassAllowPrivate(Symbols::_List())); | 30 core_lib.LookupClassAllowPrivate(Symbols::_List())); |
| 68 ASSERT(!cls.IsNull()); | 31 ASSERT(!cls.IsNull()); |
| 69 ASSERT(cls.NumTypeArguments() == 1); | 32 ASSERT(cls.NumTypeArguments() == 1); |
| 70 const intptr_t field_offset = cls.type_arguments_field_offset(); | 33 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 71 ASSERT(field_offset != Class::kNoTypeArguments); | 34 ASSERT(field_offset != Class::kNoTypeArguments); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 | 130 |
| 168 // Set the length field in the growable array object to 0. | 131 // Set the length field in the growable array object to 0. |
| 169 __ LoadImmediate(R1, 0, kNoPP); | 132 __ LoadImmediate(R1, 0, kNoPP); |
| 170 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 133 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 171 __ ret(); // Returns the newly allocated object in R0. | 134 __ ret(); // Returns the newly allocated object in R0. |
| 172 | 135 |
| 173 __ Bind(&fall_through); | 136 __ Bind(&fall_through); |
| 174 } | 137 } |
| 175 | 138 |
| 176 | 139 |
| 177 void Intrinsifier::GrowableArrayLength(Assembler* assembler) { | |
| 178 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 179 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); | |
| 180 __ ret(); | |
| 181 } | |
| 182 | |
| 183 | |
| 184 void Intrinsifier::GrowableArrayCapacity(Assembler* assembler) { | |
| 185 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 186 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); | |
| 187 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | |
| 188 __ ret(); | |
| 189 } | |
| 190 | |
| 191 | |
| 192 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { | 140 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { |
| 193 Label fall_through; | 141 Label fall_through; |
| 194 | 142 |
| 195 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 143 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 196 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 144 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 197 | 145 |
| 198 __ tsti(R0, kSmiTagMask); | 146 __ tsti(R0, kSmiTagMask); |
| 199 __ b(&fall_through, NE); // Index is not an smi, fall through. | 147 __ b(&fall_through, NE); // Index is not an smi, fall through. |
| 200 | 148 |
| 201 // Range check. | 149 // Range check. |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 __ add(R1, R2, Operand(R1, LSL, 2)); | 257 __ add(R1, R2, Operand(R1, LSL, 2)); |
| 310 __ StoreIntoObject(R2, | 258 __ StoreIntoObject(R2, |
| 311 FieldAddress(R1, Array::data_offset()), | 259 FieldAddress(R1, Array::data_offset()), |
| 312 R0); | 260 R0); |
| 313 __ LoadObject(R0, Object::null_object(), PP); | 261 __ LoadObject(R0, Object::null_object(), PP); |
| 314 __ ret(); | 262 __ ret(); |
| 315 __ Bind(&fall_through); | 263 __ Bind(&fall_through); |
| 316 } | 264 } |
| 317 | 265 |
| 318 | 266 |
| 319 // Gets the length of a TypedData. | |
| 320 void Intrinsifier::TypedDataLength(Assembler* assembler) { | |
| 321 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 322 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); | |
| 323 __ ret(); | |
| 324 } | |
| 325 | |
| 326 | |
| 327 void Intrinsifier::Uint8ArrayGetIndexed(Assembler* assembler) { | |
| 328 Label fall_through; | |
| 329 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | |
| 330 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | |
| 331 __ tsti(R0, kSmiTagMask); | |
| 332 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 333 | |
| 334 // Range check. | |
| 335 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 336 __ cmp(R0, Operand(R6)); | |
| 337 __ b(&fall_through, CS); | |
| 338 | |
| 339 // Array element at R1 + R0 + TypedData::data_offset - 1. | |
| 340 // Untag R0. | |
| 341 __ add(R1, R1, Operand(R0, LSR, 1)); | |
| 342 __ ldr(R0, FieldAddress(R1, TypedData::data_offset()), kUnsignedByte); | |
| 343 __ SmiTag(R0); | |
| 344 __ ret(); | |
| 345 __ Bind(&fall_through); | |
| 346 } | |
| 347 | |
| 348 | |
| 349 void Intrinsifier::ExternalUint8ArrayGetIndexed(Assembler* assembler) { | |
| 350 Label fall_through; | |
| 351 | |
| 352 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | |
| 353 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | |
| 354 __ tsti(R0, kSmiTagMask); | |
| 355 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 356 | |
| 357 // Range check. | |
| 358 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 359 __ cmp(R0, Operand(R6)); | |
| 360 __ b(&fall_through, CS); | |
| 361 | |
| 362 __ ldr(R1, FieldAddress(R1, ExternalTypedData::data_offset())); | |
| 363 | |
| 364 // Untag R0. | |
| 365 __ add(R1, R1, Operand(R0, LSR, 1)); | |
| 366 __ ldr(R0, Address(R1, 0), kUnsignedByte); | |
| 367 __ SmiTag(R0); | |
| 368 __ ret(); | |
| 369 __ Bind(&fall_through); | |
| 370 } | |
| 371 | |
| 372 | |
| 373 void Intrinsifier::Float64ArrayGetIndexed(Assembler* assembler) { | |
| 374 Label fall_through; | |
| 375 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | |
| 376 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | |
| 377 __ tsti(R0, kSmiTagMask); | |
| 378 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 379 | |
| 380 // Range check. | |
| 381 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 382 __ cmp(R0, Operand(R6)); | |
| 383 __ b(&fall_through, CS); | |
| 384 | |
| 385 Address element_address = | |
| 386 __ ElementAddressForRegIndex(true, // Load. | |
| 387 false, // Not external. | |
| 388 kTypedDataFloat64ArrayCid, // Cid. | |
| 389 8, // Index scale. | |
| 390 R1, // Array. | |
| 391 R0); // Index. | |
| 392 | |
| 393 __ fldrd(V0, element_address); | |
| 394 | |
| 395 const Class& double_class = Class::Handle( | |
| 396 Isolate::Current()->object_store()->double_class()); | |
| 397 __ TryAllocate(double_class, | |
| 398 &fall_through, | |
| 399 R0, // Result register. | |
| 400 R1, // Temp register. | |
| 401 kNoPP); | |
| 402 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); | |
| 403 __ ret(); | |
| 404 __ Bind(&fall_through); | |
| 405 } | |
| 406 | |
| 407 | |
| 408 void Intrinsifier::Float64ArraySetIndexed(Assembler* assembler) { | |
| 409 Label fall_through; | |
| 410 __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index. | |
| 411 __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array. | |
| 412 __ tsti(R0, kSmiTagMask); | |
| 413 __ b(&fall_through, NE); // Index is not a smi, fall through. | |
| 414 | |
| 415 // Range check. | |
| 416 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | |
| 417 __ cmp(R0, Operand(R6)); | |
| 418 __ b(&fall_through, CS); | |
| 419 | |
| 420 __ ldr(R2, Address(SP, + 0 * kWordSize)); // Value. | |
| 421 __ tsti(R2, kSmiTagMask); | |
| 422 __ b(&fall_through, EQ); // Value is Smi, fall through. | |
| 423 | |
| 424 __ LoadClassId(R3, R2, kNoPP); | |
| 425 __ CompareImmediate(R3, kDoubleCid, kNoPP); | |
| 426 __ b(&fall_through, NE); // Not a Double, fall through. | |
| 427 | |
| 428 __ LoadDFieldFromOffset(V0, R2, Double::value_offset(), kNoPP); | |
| 429 | |
| 430 Address element_address = | |
| 431 __ ElementAddressForRegIndex(false, // Store. | |
| 432 false, // Not external. | |
| 433 kTypedDataFloat64ArrayCid, // Cid. | |
| 434 8, // Index scale. | |
| 435 R1, // Array. | |
| 436 R0); // Index. | |
| 437 __ fstrd(V0, element_address); | |
| 438 __ ret(); | |
| 439 __ Bind(&fall_through); | |
| 440 } | |
| 441 | |
| 442 | |
| 443 static int GetScaleFactor(intptr_t size) { | 267 static int GetScaleFactor(intptr_t size) { |
| 444 switch (size) { | 268 switch (size) { |
| 445 case 1: return 0; | 269 case 1: return 0; |
| 446 case 2: return 1; | 270 case 2: return 1; |
| 447 case 4: return 2; | 271 case 4: return 2; |
| 448 case 8: return 3; | 272 case 8: return 3; |
| 449 case 16: return 4; | 273 case 16: return 4; |
| 450 } | 274 } |
| 451 UNREACHABLE(); | 275 UNREACHABLE(); |
| 452 return -1; | 276 return -1; |
| (...skipping 796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1249 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1073 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1250 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | 1074 __ ldr(R0, FieldAddress(R0, String::hash_offset())); |
| 1251 __ CompareRegisters(R0, ZR); | 1075 __ CompareRegisters(R0, ZR); |
| 1252 __ b(&fall_through, EQ); | 1076 __ b(&fall_through, EQ); |
| 1253 __ ret(); | 1077 __ ret(); |
| 1254 // Hash not yet computed. | 1078 // Hash not yet computed. |
| 1255 __ Bind(&fall_through); | 1079 __ Bind(&fall_through); |
| 1256 } | 1080 } |
| 1257 | 1081 |
| 1258 | 1082 |
| 1259 void Intrinsifier::StringBaseLength(Assembler* assembler) { | |
| 1260 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 1261 __ ldr(R0, FieldAddress(R0, String::length_offset())); | |
| 1262 __ ret(); | |
| 1263 } | |
| 1264 | |
| 1265 | |
| 1266 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { | 1083 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { |
| 1267 Label fall_through, try_two_byte_string; | 1084 Label fall_through, try_two_byte_string; |
| 1268 | 1085 |
| 1269 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1086 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1270 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1087 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1271 __ tsti(R1, kSmiTagMask); | 1088 __ tsti(R1, kSmiTagMask); |
| 1272 __ b(&fall_through, NE); // Index is not a Smi. | 1089 __ b(&fall_through, NE); // Index is not a Smi. |
| 1273 // Range check. | 1090 // Range check. |
| 1274 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1091 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1275 __ cmp(R1, Operand(R2)); | 1092 __ cmp(R1, Operand(R2)); |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1682 Isolate* isolate = Isolate::Current(); | 1499 Isolate* isolate = Isolate::Current(); |
| 1683 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); | 1500 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); |
| 1684 // Set return value to Isolate::current_tag_. | 1501 // Set return value to Isolate::current_tag_. |
| 1685 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); | 1502 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); |
| 1686 __ ret(); | 1503 __ ret(); |
| 1687 } | 1504 } |
| 1688 | 1505 |
| 1689 } // namespace dart | 1506 } // namespace dart |
| 1690 | 1507 |
| 1691 #endif // defined TARGET_ARCH_ARM64 | 1508 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |