| 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" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 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. |
| 34 __ andi(CMPRES, T3, Immediate(kSmiTagMask)); | 34 __ andi(CMPRES1, T3, Immediate(kSmiTagMask)); |
| 35 __ bne(CMPRES, ZR, &fall_through); | 35 __ bne(CMPRES1, ZR, &fall_through); |
| 36 __ bltz(T3, &fall_through); | 36 __ bltz(T3, &fall_through); |
| 37 | 37 |
| 38 // Check for maximum allowed length. | 38 // Check for maximum allowed length. |
| 39 const intptr_t max_len = | 39 const intptr_t max_len = |
| 40 reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements)); | 40 reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements)); |
| 41 __ BranchUnsignedGreater(T3, max_len, &fall_through); | 41 __ BranchUnsignedGreater(T3, max_len, &fall_through); |
| 42 | 42 |
| 43 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; | 43 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 44 __ LoadImmediate(T2, fixed_size); | 44 __ LoadImmediate(T2, fixed_size); |
| 45 __ sll(T3, T3, 1); // T3 is a Smi. | 45 __ sll(T3, T3, 1); // T3 is a Smi. |
| 46 __ addu(T2, T2, T3); | 46 __ addu(T2, T2, T3); |
| 47 ASSERT(kSmiTagShift == 1); | 47 ASSERT(kSmiTagShift == 1); |
| 48 __ LoadImmediate(T3, ~(kObjectAlignment - 1)); | 48 __ LoadImmediate(T3, ~(kObjectAlignment - 1)); |
| 49 __ and_(T2, T2, T3); | 49 __ and_(T2, T2, T3); |
| 50 | 50 |
| 51 // T2: Allocation size. | 51 // T2: Allocation size. |
| 52 | 52 |
| 53 Isolate* isolate = Isolate::Current(); | 53 Isolate* isolate = Isolate::Current(); |
| 54 Heap* heap = isolate->heap(); | 54 Heap* heap = isolate->heap(); |
| 55 | 55 |
| 56 __ LoadImmediate(T3, heap->TopAddress()); | 56 __ LoadImmediate(T3, heap->TopAddress()); |
| 57 __ lw(T0, Address(T3, 0)); // Potential new object start. | 57 __ lw(T0, Address(T3, 0)); // Potential new object start. |
| 58 | 58 |
| 59 __ AdduDetectOverflow(T1, T0, T2, CMPRES); // Potential next object start. | 59 __ AdduDetectOverflow(T1, T0, T2, CMPRES1); // Potential next object start. |
| 60 __ bltz(CMPRES, &fall_through); // CMPRES < 0 on overflow. | 60 __ bltz(CMPRES1, &fall_through); // CMPRES1 < 0 on overflow. |
| 61 | 61 |
| 62 // Check if the allocation fits into the remaining space. | 62 // Check if the allocation fits into the remaining space. |
| 63 // T0: potential new object start. | 63 // T0: potential new object start. |
| 64 // T1: potential next object start. | 64 // T1: potential next object start. |
| 65 // T2: allocation size. | 65 // T2: allocation size. |
| 66 __ LoadImmediate(T4, heap->TopAddress()); | 66 __ LoadImmediate(T4, heap->TopAddress()); |
| 67 __ lw(T4, Address(T4, 0)); | 67 __ lw(T4, Address(T4, 0)); |
| 68 __ BranchUnsignedGreaterEqual(T1, T4, &fall_through); | 68 __ BranchUnsignedGreaterEqual(T1, T4, &fall_through); |
| 69 | 69 |
| 70 // Successfully allocated the object(s), now update top to point to | 70 // Successfully allocated the object(s), now update top to point to |
| (...skipping 12 matching lines...) Expand all Loading... |
| 83 | 83 |
| 84 __ BranchUnsignedGreater(T2, RawObject::SizeTag::kMaxSizeTag, &overflow); | 84 __ BranchUnsignedGreater(T2, RawObject::SizeTag::kMaxSizeTag, &overflow); |
| 85 __ b(&done); | 85 __ b(&done); |
| 86 __ delay_slot()->sll(T2, T2, shift); | 86 __ delay_slot()->sll(T2, T2, shift); |
| 87 __ Bind(&overflow); | 87 __ Bind(&overflow); |
| 88 __ mov(T2, ZR); | 88 __ mov(T2, ZR); |
| 89 __ Bind(&done); | 89 __ Bind(&done); |
| 90 | 90 |
| 91 // Get the class index and insert it into the tags. | 91 // Get the class index and insert it into the tags. |
| 92 // T2: size and bit tags. | 92 // T2: size and bit tags. |
| 93 __ LoadImmediate(TMP1, RawObject::ClassIdTag::encode(cls.id())); | 93 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cls.id())); |
| 94 __ or_(T2, T2, TMP1); | 94 __ or_(T2, T2, TMP); |
| 95 __ sw(T2, FieldAddress(T0, Array::tags_offset())); // Store tags. | 95 __ sw(T2, FieldAddress(T0, Array::tags_offset())); // Store tags. |
| 96 } | 96 } |
| 97 | 97 |
| 98 // T0: new object start as a tagged pointer. | 98 // T0: new object start as a tagged pointer. |
| 99 // T1: new object end address. | 99 // T1: new object end address. |
| 100 // Store the type argument field. | 100 // Store the type argument field. |
| 101 __ lw(T2, Address(SP, kTypeArgumentsOffset)); // Type argument. | 101 __ lw(T2, Address(SP, kTypeArgumentsOffset)); // Type argument. |
| 102 __ StoreIntoObjectNoBarrier(T0, | 102 __ StoreIntoObjectNoBarrier(T0, |
| 103 FieldAddress(T0, Array::type_arguments_offset()), | 103 FieldAddress(T0, Array::type_arguments_offset()), |
| 104 T2); | 104 T2); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 void Intrinsifier::ImmutableList_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(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 154 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through | 154 __ bne(CMPRES1, 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); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 // Check if it's dynamic. | 210 // Check if it's dynamic. |
| 211 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. | 211 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. |
| 212 __ LoadClassId(CMPRES1, T1); | 212 __ LoadClassId(CMPRES1, T1); |
| 213 __ BranchNotEqual(CMPRES1, kTypeArgumentsCid, &fall_through); | 213 __ BranchNotEqual(CMPRES1, kTypeArgumentsCid, &fall_through); |
| 214 | 214 |
| 215 // Get type at index 0. | 215 // Get type at index 0. |
| 216 __ lw(T0, FieldAddress(T1, TypeArguments::type_at_offset(0))); | 216 __ lw(T0, FieldAddress(T1, TypeArguments::type_at_offset(0))); |
| 217 __ BranchEqual(T0, Type::ZoneHandle(Type::DynamicType()), &checked_ok); | 217 __ BranchEqual(T0, Type::ZoneHandle(Type::DynamicType()), &checked_ok); |
| 218 | 218 |
| 219 // Check for int and num. | 219 // Check for int and num. |
| 220 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); | 220 __ andi(CMPRES1, T2, Immediate(kSmiTagMask)); |
| 221 __ bne(CMPRES, ZR, &fall_through); // Non-smi value. | 221 __ bne(CMPRES1, ZR, &fall_through); // Non-smi value. |
| 222 | 222 |
| 223 __ BranchEqual(T0, Type::ZoneHandle(Type::IntType()), &checked_ok); | 223 __ BranchEqual(T0, Type::ZoneHandle(Type::IntType()), &checked_ok); |
| 224 __ BranchNotEqual(T0, Type::ZoneHandle(Type::Number()), &fall_through); | 224 __ BranchNotEqual(T0, Type::ZoneHandle(Type::Number()), &fall_through); |
| 225 __ Bind(&checked_ok); | 225 __ Bind(&checked_ok); |
| 226 } | 226 } |
| 227 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. | 227 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. |
| 228 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 228 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 229 // Index not Smi. | 229 // Index not Smi. |
| 230 __ bne(CMPRES, ZR, &fall_through); | 230 __ bne(CMPRES1, ZR, &fall_through); |
| 231 | 231 |
| 232 __ lw(T0, Address(SP, 2 * kWordSize)); // Array. | 232 __ lw(T0, Address(SP, 2 * kWordSize)); // Array. |
| 233 // Range check. | 233 // Range check. |
| 234 __ lw(T3, FieldAddress(T0, Array::length_offset())); // Array length. | 234 __ lw(T3, FieldAddress(T0, Array::length_offset())); // Array length. |
| 235 // Runtime throws exception. | 235 // Runtime throws exception. |
| 236 __ BranchUnsignedGreaterEqual(T1, T3, &fall_through); | 236 __ BranchUnsignedGreaterEqual(T1, T3, &fall_through); |
| 237 | 237 |
| 238 // Note that T1 is Smi, i.e, times 2. | 238 // Note that T1 is Smi, i.e, times 2. |
| 239 ASSERT(kSmiTagShift == 1); | 239 ASSERT(kSmiTagShift == 1); |
| 240 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 240 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 __ Ret(); | 330 __ Ret(); |
| 331 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); | 331 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); |
| 332 } | 332 } |
| 333 | 333 |
| 334 | 334 |
| 335 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { | 335 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { |
| 336 Label fall_through; | 336 Label fall_through; |
| 337 | 337 |
| 338 __ lw(T0, Address(SP, 0 * kWordSize)); // Index | 338 __ lw(T0, Address(SP, 0 * kWordSize)); // Index |
| 339 | 339 |
| 340 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 340 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 341 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through | 341 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through |
| 342 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array | 342 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array |
| 343 | 343 |
| 344 // range check | 344 // range check |
| 345 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); | 345 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); |
| 346 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 346 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 347 | 347 |
| 348 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data | 348 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data |
| 349 | 349 |
| 350 ASSERT(kSmiTagShift == 1); | 350 ASSERT(kSmiTagShift == 1); |
| 351 // array element at T2 + T0 * 2 + Array::data_offset - 1 | 351 // array element at T2 + T0 * 2 + Array::data_offset - 1 |
| 352 __ sll(T3, T0, 1); | 352 __ sll(T3, T0, 1); |
| 353 __ addu(T2, T2, T3); | 353 __ addu(T2, T2, T3); |
| 354 __ Ret(); | 354 __ Ret(); |
| 355 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); | 355 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); |
| 356 __ Bind(&fall_through); | 356 __ Bind(&fall_through); |
| 357 } | 357 } |
| 358 | 358 |
| 359 | 359 |
| 360 // Set value into growable object array at specified index. | 360 // Set value into growable object array at specified index. |
| 361 // On stack: growable array (+2), index (+1), value (+0). | 361 // On stack: growable array (+2), index (+1), value (+0). |
| 362 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { | 362 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { |
| 363 if (FLAG_enable_type_checks) { | 363 if (FLAG_enable_type_checks) { |
| 364 return; | 364 return; |
| 365 } | 365 } |
| 366 Label fall_through; | 366 Label fall_through; |
| 367 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. | 367 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. |
| 368 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 368 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 369 __ bne(CMPRES, ZR, &fall_through); // Non-smi index. | 369 __ bne(CMPRES1, ZR, &fall_through); // Non-smi index. |
| 370 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. | 370 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 371 // Range check using _length field. | 371 // Range check using _length field. |
| 372 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); | 372 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 373 // Runtime throws exception. | 373 // Runtime throws exception. |
| 374 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); | 374 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); |
| 375 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. | 375 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. |
| 376 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 376 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 377 // Note that T1 is Smi, i.e, times 2. | 377 // Note that T1 is Smi, i.e, times 2. |
| 378 ASSERT(kSmiTagShift == 1); | 378 ASSERT(kSmiTagShift == 1); |
| 379 __ sll(T1, T1, 1); | 379 __ sll(T1, T1, 1); |
| 380 __ addu(T1, T0, T1); | 380 __ addu(T1, T0, T1); |
| 381 __ StoreIntoObject(T0, | 381 __ StoreIntoObject(T0, |
| 382 FieldAddress(T1, Array::data_offset()), | 382 FieldAddress(T1, Array::data_offset()), |
| 383 T2); | 383 T2); |
| 384 __ Ret(); | 384 __ Ret(); |
| 385 __ Bind(&fall_through); | 385 __ Bind(&fall_through); |
| 386 } | 386 } |
| 387 | 387 |
| 388 | 388 |
| 389 // Set length of growable object array. The length cannot | 389 // Set length of growable object array. The length cannot |
| 390 // be greater than the length of the data container. | 390 // be greater than the length of the data container. |
| 391 // On stack: growable array (+1), length (+0). | 391 // On stack: growable array (+1), length (+0). |
| 392 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { | 392 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { |
| 393 Label fall_through; | 393 Label fall_through; |
| 394 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. | 394 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. |
| 395 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 395 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 396 __ bne(CMPRES, ZR, &fall_through); // Non-smi length. | 396 __ bne(CMPRES1, ZR, &fall_through); // Non-smi length. |
| 397 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 397 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 398 __ Ret(); | 398 __ Ret(); |
| 399 __ delay_slot()->sw(T1, | 399 __ delay_slot()->sw(T1, |
| 400 FieldAddress(T0, GrowableObjectArray::length_offset())); | 400 FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 401 __ Bind(&fall_through); | 401 __ Bind(&fall_through); |
| 402 } | 402 } |
| 403 | 403 |
| 404 | 404 |
| 405 // Set data of growable object array. | 405 // Set data of growable object array. |
| 406 // On stack: growable array (+1), data (+0). | 406 // On stack: growable array (+1), data (+0). |
| 407 void Intrinsifier::GrowableList_setData(Assembler* assembler) { | 407 void Intrinsifier::GrowableList_setData(Assembler* assembler) { |
| 408 if (FLAG_enable_type_checks) { | 408 if (FLAG_enable_type_checks) { |
| 409 return; | 409 return; |
| 410 } | 410 } |
| 411 Label fall_through; | 411 Label fall_through; |
| 412 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. | 412 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. |
| 413 // Check that data is an ObjectArray. | 413 // Check that data is an ObjectArray. |
| 414 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 414 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 415 __ beq(CMPRES, ZR, &fall_through); // Data is Smi. | 415 __ beq(CMPRES1, ZR, &fall_through); // Data is Smi. |
| 416 __ LoadClassId(CMPRES1, T1); | 416 __ LoadClassId(CMPRES1, T1); |
| 417 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); | 417 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); |
| 418 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 418 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 419 __ StoreIntoObject(T0, | 419 __ StoreIntoObject(T0, |
| 420 FieldAddress(T0, GrowableObjectArray::data_offset()), | 420 FieldAddress(T0, GrowableObjectArray::data_offset()), |
| 421 T1); | 421 T1); |
| 422 __ Ret(); | 422 __ Ret(); |
| 423 __ Bind(&fall_through); | 423 __ Bind(&fall_through); |
| 424 } | 424 } |
| 425 | 425 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 __ Bind(&fall_through); | 457 __ Bind(&fall_through); |
| 458 } | 458 } |
| 459 | 459 |
| 460 | 460 |
| 461 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ | 461 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ |
| 462 Label fall_through; \ | 462 Label fall_through; \ |
| 463 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ | 463 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ |
| 464 __ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ | 464 __ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ |
| 465 /* Check that length is a positive Smi. */ \ | 465 /* Check that length is a positive Smi. */ \ |
| 466 /* T2: requested array length argument. */ \ | 466 /* T2: requested array length argument. */ \ |
| 467 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); \ | 467 __ andi(CMPRES1, T2, Immediate(kSmiTagMask)); \ |
| 468 __ bne(CMPRES, ZR, &fall_through); \ | 468 __ bne(CMPRES1, ZR, &fall_through); \ |
| 469 __ BranchSignedLess(T2, 0, &fall_through); \ | 469 __ BranchSignedLess(T2, 0, &fall_through); \ |
| 470 __ SmiUntag(T2); \ | 470 __ SmiUntag(T2); \ |
| 471 /* Check for maximum allowed length. */ \ | 471 /* Check for maximum allowed length. */ \ |
| 472 /* T2: untagged array length. */ \ | 472 /* T2: untagged array length. */ \ |
| 473 __ BranchSignedGreater(T2, max_len, &fall_through); \ | 473 __ BranchSignedGreater(T2, max_len, &fall_through); \ |
| 474 __ sll(T2, T2, scale_shift); \ | 474 __ sll(T2, T2, scale_shift); \ |
| 475 const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \ | 475 const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \ |
| 476 __ AddImmediate(T2, fixed_size); \ | 476 __ AddImmediate(T2, fixed_size); \ |
| 477 __ LoadImmediate(TMP, -kObjectAlignment); \ | 477 __ LoadImmediate(TMP, -kObjectAlignment); \ |
| 478 __ and_(T2, T2, TMP); \ | 478 __ and_(T2, T2, TMP); \ |
| 479 Heap* heap = Isolate::Current()->heap(); \ | 479 Heap* heap = Isolate::Current()->heap(); \ |
| 480 \ | 480 \ |
| 481 __ LoadImmediate(V0, heap->TopAddress()); \ | 481 __ LoadImmediate(V0, heap->TopAddress()); \ |
| 482 __ lw(V0, Address(V0, 0)); \ | 482 __ lw(V0, Address(V0, 0)); \ |
| 483 \ | 483 \ |
| 484 /* T2: allocation size. */ \ | 484 /* T2: allocation size. */ \ |
| 485 __ AdduDetectOverflow(T1, V0, T2, CMPRES); \ | 485 __ AdduDetectOverflow(T1, V0, T2, CMPRES1); \ |
| 486 __ bltz(CMPRES, &fall_through); \ | 486 __ bltz(CMPRES1, &fall_through); \ |
| 487 \ | 487 \ |
| 488 /* Check if the allocation fits into the remaining space. */ \ | 488 /* Check if the allocation fits into the remaining space. */ \ |
| 489 /* V0: potential new object start. */ \ | 489 /* V0: potential new object start. */ \ |
| 490 /* T1: potential next object start. */ \ | 490 /* T1: potential next object start. */ \ |
| 491 /* T2: allocation size. */ \ | 491 /* T2: allocation size. */ \ |
| 492 __ LoadImmediate(T3, heap->EndAddress()); \ | 492 __ LoadImmediate(T3, heap->EndAddress()); \ |
| 493 __ lw(T3, Address(T3, 0)); \ | 493 __ lw(T3, Address(T3, 0)); \ |
| 494 __ BranchUnsignedGreaterEqual(T1, T3, &fall_through); \ | 494 __ BranchUnsignedGreaterEqual(T1, T3, &fall_through); \ |
| 495 \ | 495 \ |
| 496 /* Successfully allocated the object(s), now update top to point to */ \ | 496 /* Successfully allocated the object(s), now update top to point to */ \ |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 } | 581 } |
| 582 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 582 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
| 583 #undef TYPED_DATA_ALLOCATOR | 583 #undef TYPED_DATA_ALLOCATOR |
| 584 | 584 |
| 585 | 585 |
| 586 // Loads args from stack into T0 and T1 | 586 // Loads args from stack into T0 and T1 |
| 587 // Tests if they are smis, jumps to label not_smi if not. | 587 // Tests if they are smis, jumps to label not_smi if not. |
| 588 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 588 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 589 __ lw(T0, Address(SP, 0 * kWordSize)); | 589 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 590 __ lw(T1, Address(SP, 1 * kWordSize)); | 590 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 591 __ or_(CMPRES, T0, T1); | 591 __ or_(CMPRES1, T0, T1); |
| 592 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); | 592 __ andi(CMPRES1, CMPRES1, Immediate(kSmiTagMask)); |
| 593 __ bne(CMPRES, ZR, not_smi); | 593 __ bne(CMPRES1, ZR, not_smi); |
| 594 return; | 594 return; |
| 595 } | 595 } |
| 596 | 596 |
| 597 | 597 |
| 598 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 598 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
| 599 Label fall_through; | 599 Label fall_through; |
| 600 | 600 |
| 601 TestBothArgumentsSmis(assembler, &fall_through); // Checks two Smis. | 601 TestBothArgumentsSmis(assembler, &fall_through); // Checks two Smis. |
| 602 __ AdduDetectOverflow(V0, T0, T1, CMPRES); // Add. | 602 __ AdduDetectOverflow(V0, T0, T1, CMPRES1); // Add. |
| 603 __ bltz(CMPRES, &fall_through); // Fall through on overflow. | 603 __ bltz(CMPRES1, &fall_through); // Fall through on overflow. |
| 604 __ Ret(); // Nothing in branch delay slot. | 604 __ Ret(); // Nothing in branch delay slot. |
| 605 __ Bind(&fall_through); | 605 __ Bind(&fall_through); |
| 606 } | 606 } |
| 607 | 607 |
| 608 | 608 |
| 609 void Intrinsifier::Integer_add(Assembler* assembler) { | 609 void Intrinsifier::Integer_add(Assembler* assembler) { |
| 610 return Integer_addFromInteger(assembler); | 610 return Integer_addFromInteger(assembler); |
| 611 } | 611 } |
| 612 | 612 |
| 613 | 613 |
| 614 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 614 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
| 615 Label fall_through; | 615 Label fall_through; |
| 616 | 616 |
| 617 TestBothArgumentsSmis(assembler, &fall_through); | 617 TestBothArgumentsSmis(assembler, &fall_through); |
| 618 __ SubuDetectOverflow(V0, T0, T1, CMPRES); // Subtract. | 618 __ SubuDetectOverflow(V0, T0, T1, CMPRES1); // Subtract. |
| 619 __ bltz(CMPRES, &fall_through); // Fall through on overflow. | 619 __ bltz(CMPRES1, &fall_through); // Fall through on overflow. |
| 620 __ Ret(); | 620 __ Ret(); |
| 621 __ Bind(&fall_through); | 621 __ Bind(&fall_through); |
| 622 } | 622 } |
| 623 | 623 |
| 624 | 624 |
| 625 void Intrinsifier::Integer_sub(Assembler* assembler) { | 625 void Intrinsifier::Integer_sub(Assembler* assembler) { |
| 626 Label fall_through; | 626 Label fall_through; |
| 627 | 627 |
| 628 TestBothArgumentsSmis(assembler, &fall_through); | 628 TestBothArgumentsSmis(assembler, &fall_through); |
| 629 __ SubuDetectOverflow(V0, T1, T0, CMPRES); // Subtract. | 629 __ SubuDetectOverflow(V0, T1, T0, CMPRES1); // Subtract. |
| 630 __ bltz(CMPRES, &fall_through); // Fall through on overflow. | 630 __ bltz(CMPRES1, &fall_through); // Fall through on overflow. |
| 631 __ Ret(); // Nothing in branch delay slot. | 631 __ Ret(); // Nothing in branch delay slot. |
| 632 __ Bind(&fall_through); | 632 __ Bind(&fall_through); |
| 633 } | 633 } |
| 634 | 634 |
| 635 | 635 |
| 636 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 636 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
| 637 Label fall_through; | 637 Label fall_through; |
| 638 | 638 |
| 639 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis | 639 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis |
| 640 __ SmiUntag(T0); // untags T0. only want result shifted by one | 640 __ SmiUntag(T0); // untags T0. only want result shifted by one |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 // res = res - right; | 699 // res = res - right; |
| 700 // } else { | 700 // } else { |
| 701 // res = res + right; | 701 // res = res + right; |
| 702 // } | 702 // } |
| 703 // } | 703 // } |
| 704 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 704 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
| 705 Label fall_through, subtract; | 705 Label fall_through, subtract; |
| 706 // Test arguments for smi. | 706 // Test arguments for smi. |
| 707 __ lw(T1, Address(SP, 0 * kWordSize)); | 707 __ lw(T1, Address(SP, 0 * kWordSize)); |
| 708 __ lw(T0, Address(SP, 1 * kWordSize)); | 708 __ lw(T0, Address(SP, 1 * kWordSize)); |
| 709 __ or_(CMPRES, T0, T1); | 709 __ or_(CMPRES1, T0, T1); |
| 710 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); | 710 __ andi(CMPRES1, CMPRES1, Immediate(kSmiTagMask)); |
| 711 __ bne(CMPRES, ZR, &fall_through); | 711 __ bne(CMPRES1, ZR, &fall_through); |
| 712 // T1: Tagged left (dividend). | 712 // T1: Tagged left (dividend). |
| 713 // T0: Tagged right (divisor). | 713 // T0: Tagged right (divisor). |
| 714 // Check if modulo by zero -> exception thrown in main function. | 714 // Check if modulo by zero -> exception thrown in main function. |
| 715 __ beq(T0, ZR, &fall_through); | 715 __ beq(T0, ZR, &fall_through); |
| 716 EmitRemainderOperation(assembler); | 716 EmitRemainderOperation(assembler); |
| 717 // Untagged right in T0. Untagged remainder result in V0. | 717 // Untagged right in T0. Untagged remainder result in V0. |
| 718 | 718 |
| 719 Label done; | 719 Label done; |
| 720 __ bgez(V0, &done); | 720 __ bgez(V0, &done); |
| 721 __ bltz(T0, &subtract); | 721 __ bltz(T0, &subtract); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 752 __ Ret(); | 752 __ Ret(); |
| 753 __ delay_slot()->SmiTag(V0); | 753 __ delay_slot()->SmiTag(V0); |
| 754 __ Bind(&fall_through); | 754 __ Bind(&fall_through); |
| 755 } | 755 } |
| 756 | 756 |
| 757 | 757 |
| 758 void Intrinsifier::Integer_negate(Assembler* assembler) { | 758 void Intrinsifier::Integer_negate(Assembler* assembler) { |
| 759 Label fall_through; | 759 Label fall_through; |
| 760 | 760 |
| 761 __ lw(T0, Address(SP, + 0 * kWordSize)); // Grabs first argument. | 761 __ lw(T0, Address(SP, + 0 * kWordSize)); // Grabs first argument. |
| 762 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); // Test for Smi. | 762 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); // Test for Smi. |
| 763 __ bne(CMPRES, ZR, &fall_through); // Fall through if not a Smi. | 763 __ bne(CMPRES1, ZR, &fall_through); // Fall through if not a Smi. |
| 764 __ SubuDetectOverflow(V0, ZR, T0, CMPRES); | 764 __ SubuDetectOverflow(V0, ZR, T0, CMPRES1); |
| 765 __ bltz(CMPRES, &fall_through); // There was overflow. | 765 __ bltz(CMPRES1, &fall_through); // There was overflow. |
| 766 __ Ret(); | 766 __ Ret(); |
| 767 __ Bind(&fall_through); | 767 __ Bind(&fall_through); |
| 768 } | 768 } |
| 769 | 769 |
| 770 | 770 |
| 771 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 771 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
| 772 Label fall_through; | 772 Label fall_through; |
| 773 | 773 |
| 774 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. | 774 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. |
| 775 __ Ret(); | 775 __ Ret(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 __ Bind(&fall_through); | 862 __ Bind(&fall_through); |
| 863 } | 863 } |
| 864 | 864 |
| 865 | 865 |
| 866 static void Get64SmiOrMint(Assembler* assembler, | 866 static void Get64SmiOrMint(Assembler* assembler, |
| 867 Register res_hi, | 867 Register res_hi, |
| 868 Register res_lo, | 868 Register res_lo, |
| 869 Register reg, | 869 Register reg, |
| 870 Label* not_smi_or_mint) { | 870 Label* not_smi_or_mint) { |
| 871 Label not_smi, done; | 871 Label not_smi, done; |
| 872 __ andi(CMPRES, reg, Immediate(kSmiTagMask)); | 872 __ andi(CMPRES1, reg, Immediate(kSmiTagMask)); |
| 873 __ bne(CMPRES, ZR, ¬_smi); | 873 __ bne(CMPRES1, ZR, ¬_smi); |
| 874 __ SmiUntag(reg); | 874 __ SmiUntag(reg); |
| 875 | 875 |
| 876 // Sign extend to 64 bit | 876 // Sign extend to 64 bit |
| 877 __ mov(res_lo, reg); | 877 __ mov(res_lo, reg); |
| 878 __ b(&done); | 878 __ b(&done); |
| 879 __ delay_slot()->sra(res_hi, reg, 31); | 879 __ delay_slot()->sra(res_hi, reg, 31); |
| 880 | 880 |
| 881 __ Bind(¬_smi); | 881 __ Bind(¬_smi); |
| 882 __ LoadClassId(CMPRES1, reg); | 882 __ LoadClassId(CMPRES1, reg); |
| 883 __ BranchNotEqual(CMPRES1, kMintCid, not_smi_or_mint); | 883 __ BranchNotEqual(CMPRES1, kMintCid, not_smi_or_mint); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 990 // This is called for Smi, Mint and Bigint receivers. The right argument | 990 // This is called for Smi, Mint and Bigint receivers. The right argument |
| 991 // can be Smi, Mint, Bigint or double. | 991 // can be Smi, Mint, Bigint or double. |
| 992 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 992 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
| 993 Label fall_through, true_label, check_for_mint; | 993 Label fall_through, true_label, check_for_mint; |
| 994 // For integer receiver '===' check first. | 994 // For integer receiver '===' check first. |
| 995 __ lw(T0, Address(SP, 0 * kWordSize)); | 995 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 996 __ lw(T1, Address(SP, 1 * kWordSize)); | 996 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 997 __ beq(T0, T1, &true_label); | 997 __ beq(T0, T1, &true_label); |
| 998 | 998 |
| 999 __ or_(T2, T0, T1); | 999 __ or_(T2, T0, T1); |
| 1000 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); | 1000 __ andi(CMPRES1, T2, Immediate(kSmiTagMask)); |
| 1001 // If T0 or T1 is not a smi do Mint checks. | 1001 // If T0 or T1 is not a smi do Mint checks. |
| 1002 __ bne(CMPRES, ZR, &check_for_mint); | 1002 __ bne(CMPRES1, ZR, &check_for_mint); |
| 1003 | 1003 |
| 1004 // Both arguments are smi, '===' is good enough. | 1004 // Both arguments are smi, '===' is good enough. |
| 1005 __ LoadObject(V0, Bool::False()); | 1005 __ LoadObject(V0, Bool::False()); |
| 1006 __ Ret(); | 1006 __ Ret(); |
| 1007 __ Bind(&true_label); | 1007 __ Bind(&true_label); |
| 1008 __ LoadObject(V0, Bool::True()); | 1008 __ LoadObject(V0, Bool::True()); |
| 1009 __ Ret(); | 1009 __ Ret(); |
| 1010 | 1010 |
| 1011 // At least one of the arguments was not Smi. | 1011 // At least one of the arguments was not Smi. |
| 1012 Label receiver_not_smi; | 1012 Label receiver_not_smi; |
| 1013 __ Bind(&check_for_mint); | 1013 __ Bind(&check_for_mint); |
| 1014 | 1014 |
| 1015 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 1015 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 1016 __ bne(CMPRES, ZR, &receiver_not_smi); // Check receiver. | 1016 __ bne(CMPRES1, ZR, &receiver_not_smi); // Check receiver. |
| 1017 | 1017 |
| 1018 // Left (receiver) is Smi, return false if right is not Double. | 1018 // Left (receiver) is Smi, return false if right is not Double. |
| 1019 // Note that an instance of Mint or Bigint never contains a value that can be | 1019 // Note that an instance of Mint or Bigint never contains a value that can be |
| 1020 // represented by Smi. | 1020 // represented by Smi. |
| 1021 | 1021 |
| 1022 __ LoadClassId(CMPRES1, T0); | 1022 __ LoadClassId(CMPRES1, T0); |
| 1023 __ BranchEqual(CMPRES1, kDoubleCid, &fall_through); | 1023 __ BranchEqual(CMPRES1, kDoubleCid, &fall_through); |
| 1024 __ LoadObject(V0, Bool::False()); // Smi == Mint -> false. | 1024 __ LoadObject(V0, Bool::False()); // Smi == Mint -> false. |
| 1025 __ Ret(); | 1025 __ Ret(); |
| 1026 | 1026 |
| 1027 __ Bind(&receiver_not_smi); | 1027 __ Bind(&receiver_not_smi); |
| 1028 // T1:: receiver. | 1028 // T1:: receiver. |
| 1029 | 1029 |
| 1030 __ LoadClassId(CMPRES1, T1); | 1030 __ LoadClassId(CMPRES1, T1); |
| 1031 __ BranchNotEqual(CMPRES1, kMintCid, &fall_through); | 1031 __ BranchNotEqual(CMPRES1, kMintCid, &fall_through); |
| 1032 // Receiver is Mint, return false if right is Smi. | 1032 // Receiver is Mint, return false if right is Smi. |
| 1033 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1033 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 1034 __ bne(CMPRES, ZR, &fall_through); | 1034 __ bne(CMPRES1, ZR, &fall_through); |
| 1035 __ LoadObject(V0, Bool::False()); | 1035 __ LoadObject(V0, Bool::False()); |
| 1036 __ Ret(); | 1036 __ Ret(); |
| 1037 // TODO(srdjan): Implement Mint == Mint comparison. | 1037 // TODO(srdjan): Implement Mint == Mint comparison. |
| 1038 | 1038 |
| 1039 __ Bind(&fall_through); | 1039 __ Bind(&fall_through); |
| 1040 } | 1040 } |
| 1041 | 1041 |
| 1042 | 1042 |
| 1043 void Intrinsifier::Integer_equal(Assembler* assembler) { | 1043 void Intrinsifier::Integer_equal(Assembler* assembler) { |
| 1044 return Integer_equalToInteger(assembler); | 1044 return Integer_equalToInteger(assembler); |
| 1045 } | 1045 } |
| 1046 | 1046 |
| 1047 | 1047 |
| 1048 void Intrinsifier::Integer_sar(Assembler* assembler) { | 1048 void Intrinsifier::Integer_sar(Assembler* assembler) { |
| 1049 Label fall_through; | 1049 Label fall_through; |
| 1050 | 1050 |
| 1051 TestBothArgumentsSmis(assembler, &fall_through); | 1051 TestBothArgumentsSmis(assembler, &fall_through); |
| 1052 // Shift amount in T0. Value to shift in T1. | 1052 // Shift amount in T0. Value to shift in T1. |
| 1053 | 1053 |
| 1054 __ SmiUntag(T0); | 1054 __ SmiUntag(T0); |
| 1055 __ bltz(T0, &fall_through); | 1055 __ bltz(T0, &fall_through); |
| 1056 | 1056 |
| 1057 __ LoadImmediate(T2, 0x1F); | 1057 __ LoadImmediate(T2, 0x1F); |
| 1058 __ slt(CMPRES, T2, T0); // CMPRES <- 0x1F < T0 ? 1 : 0 | 1058 __ slt(CMPRES1, T2, T0); // CMPRES1 <- 0x1F < T0 ? 1 : 0 |
| 1059 __ movn(T0, T2, CMPRES); // T0 <- 0x1F < T0 ? 0x1F : T0 | 1059 __ movn(T0, T2, CMPRES1); // T0 <- 0x1F < T0 ? 0x1F : T0 |
| 1060 | 1060 |
| 1061 __ SmiUntag(T1); | 1061 __ SmiUntag(T1); |
| 1062 __ srav(V0, T1, T0); | 1062 __ srav(V0, T1, T0); |
| 1063 __ Ret(); | 1063 __ Ret(); |
| 1064 __ delay_slot()->SmiTag(V0); | 1064 __ delay_slot()->SmiTag(V0); |
| 1065 __ Bind(&fall_through); | 1065 __ Bind(&fall_through); |
| 1066 } | 1066 } |
| 1067 | 1067 |
| 1068 | 1068 |
| 1069 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 1069 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
| 1070 __ lw(T0, Address(SP, 0 * kWordSize)); | 1070 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1071 __ nor(V0, T0, ZR); | 1071 __ nor(V0, T0, ZR); |
| 1072 __ Ret(); | 1072 __ Ret(); |
| 1073 __ delay_slot()->addiu(V0, V0, Immediate(-1)); // Remove inverted smi-tag. | 1073 __ delay_slot()->addiu(V0, V0, Immediate(-1)); // Remove inverted smi-tag. |
| 1074 } | 1074 } |
| 1075 | 1075 |
| 1076 | 1076 |
| 1077 void Intrinsifier::Smi_bitLength(Assembler* assembler) { | 1077 void Intrinsifier::Smi_bitLength(Assembler* assembler) { |
| 1078 // TODO(sra): Implement. | 1078 // TODO(sra): Implement. |
| 1079 } | 1079 } |
| 1080 | 1080 |
| 1081 | 1081 |
| 1082 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1082 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 1083 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1083 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 1084 // Returns the last argument in T0. | 1084 // Returns the last argument in T0. |
| 1085 static void TestLastArgumentIsDouble(Assembler* assembler, | 1085 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 1086 Label* is_smi, | 1086 Label* is_smi, |
| 1087 Label* not_double_smi) { | 1087 Label* not_double_smi) { |
| 1088 __ lw(T0, Address(SP, 0 * kWordSize)); | 1088 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1089 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1089 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 1090 __ beq(CMPRES, ZR, is_smi); | 1090 __ beq(CMPRES1, ZR, is_smi); |
| 1091 __ LoadClassId(CMPRES1, T0); | 1091 __ LoadClassId(CMPRES1, T0); |
| 1092 __ BranchNotEqual(CMPRES1, kDoubleCid, not_double_smi); | 1092 __ BranchNotEqual(CMPRES1, kDoubleCid, not_double_smi); |
| 1093 // Fall through with Double in T0. | 1093 // Fall through with Double in T0. |
| 1094 } | 1094 } |
| 1095 | 1095 |
| 1096 | 1096 |
| 1097 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 1097 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
| 1098 // type. Return true or false object in the register V0. Any NaN argument | 1098 // type. Return true or false object in the register V0. Any NaN argument |
| 1099 // returns false. Any non-double arg1 causes control flow to fall through to the | 1099 // returns false. Any non-double arg1 causes control flow to fall through to the |
| 1100 // slow case (compiled method body). | 1100 // slow case (compiled method body). |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 void Intrinsifier::Double_div(Assembler* assembler) { | 1221 void Intrinsifier::Double_div(Assembler* assembler) { |
| 1222 return DoubleArithmeticOperations(assembler, Token::kDIV); | 1222 return DoubleArithmeticOperations(assembler, Token::kDIV); |
| 1223 } | 1223 } |
| 1224 | 1224 |
| 1225 | 1225 |
| 1226 // Left is double right is integer (Bigint, Mint or Smi) | 1226 // Left is double right is integer (Bigint, Mint or Smi) |
| 1227 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 1227 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 1228 Label fall_through; | 1228 Label fall_through; |
| 1229 // Only smis allowed. | 1229 // Only smis allowed. |
| 1230 __ lw(T0, Address(SP, 0 * kWordSize)); | 1230 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1231 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1231 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 1232 __ bne(CMPRES, ZR, &fall_through); | 1232 __ bne(CMPRES1, ZR, &fall_through); |
| 1233 | 1233 |
| 1234 // Is Smi. | 1234 // Is Smi. |
| 1235 __ SmiUntag(T0); | 1235 __ SmiUntag(T0); |
| 1236 __ mtc1(T0, F4); | 1236 __ mtc1(T0, F4); |
| 1237 __ cvtdw(D1, F4); | 1237 __ cvtdw(D1, F4); |
| 1238 | 1238 |
| 1239 __ lw(T0, Address(SP, 1 * kWordSize)); | 1239 __ lw(T0, Address(SP, 1 * kWordSize)); |
| 1240 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); | 1240 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); |
| 1241 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); | 1241 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); |
| 1242 __ muld(D0, D0, D1); | 1242 __ muld(D0, D0, D1); |
| 1243 const Class& double_class = Class::Handle( | 1243 const Class& double_class = Class::Handle( |
| 1244 Isolate::Current()->object_store()->double_class()); | 1244 Isolate::Current()->object_store()->double_class()); |
| 1245 __ TryAllocate(double_class, &fall_through, V0); // Result register. | 1245 __ TryAllocate(double_class, &fall_through, V0); // Result register. |
| 1246 __ swc1(F0, FieldAddress(V0, Double::value_offset())); | 1246 __ swc1(F0, FieldAddress(V0, Double::value_offset())); |
| 1247 __ Ret(); | 1247 __ Ret(); |
| 1248 __ delay_slot()->swc1(F1, | 1248 __ delay_slot()->swc1(F1, |
| 1249 FieldAddress(V0, Double::value_offset() + kWordSize)); | 1249 FieldAddress(V0, Double::value_offset() + kWordSize)); |
| 1250 __ Bind(&fall_through); | 1250 __ Bind(&fall_through); |
| 1251 } | 1251 } |
| 1252 | 1252 |
| 1253 | 1253 |
| 1254 void Intrinsifier::Double_fromInteger(Assembler* assembler) { | 1254 void Intrinsifier::Double_fromInteger(Assembler* assembler) { |
| 1255 Label fall_through; | 1255 Label fall_through; |
| 1256 | 1256 |
| 1257 __ lw(T0, Address(SP, 0 * kWordSize)); | 1257 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1258 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1258 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 1259 __ bne(T0, ZR, &fall_through); | 1259 __ bne(T0, ZR, &fall_through); |
| 1260 | 1260 |
| 1261 // Is Smi. | 1261 // Is Smi. |
| 1262 __ SmiUntag(T0); | 1262 __ SmiUntag(T0); |
| 1263 __ mtc1(T0, F4); | 1263 __ mtc1(T0, F4); |
| 1264 __ cvtdw(D0, F4); | 1264 __ cvtdw(D0, F4); |
| 1265 const Class& double_class = Class::Handle( | 1265 const Class& double_class = Class::Handle( |
| 1266 Isolate::Current()->object_store()->double_class()); | 1266 Isolate::Current()->object_store()->double_class()); |
| 1267 __ TryAllocate(double_class, &fall_through, V0); // Result register. | 1267 __ TryAllocate(double_class, &fall_through, V0); // Result register. |
| 1268 __ swc1(F0, FieldAddress(V0, Double::value_offset())); | 1268 __ swc1(F0, FieldAddress(V0, Double::value_offset())); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1309 __ Ret(); | 1309 __ Ret(); |
| 1310 | 1310 |
| 1311 __ Bind(&is_false); | 1311 __ Bind(&is_false); |
| 1312 __ LoadObject(V0, Bool::False()); | 1312 __ LoadObject(V0, Bool::False()); |
| 1313 __ Ret(); | 1313 __ Ret(); |
| 1314 | 1314 |
| 1315 __ Bind(&is_zero); | 1315 __ Bind(&is_zero); |
| 1316 // Check for negative zero by looking at the sign bit. | 1316 // Check for negative zero by looking at the sign bit. |
| 1317 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0. | 1317 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0. |
| 1318 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0. | 1318 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0. |
| 1319 __ andi(CMPRES, T0, Immediate(1)); // Check if the bit is set. | 1319 __ andi(CMPRES1, T0, Immediate(1)); // Check if the bit is set. |
| 1320 __ bne(T0, ZR, &is_true); // Sign bit set. True. | 1320 __ bne(T0, ZR, &is_true); // Sign bit set. True. |
| 1321 __ b(&is_false); | 1321 __ b(&is_false); |
| 1322 } | 1322 } |
| 1323 | 1323 |
| 1324 | 1324 |
| 1325 void Intrinsifier::Double_toInt(Assembler* assembler) { | 1325 void Intrinsifier::Double_toInt(Assembler* assembler) { |
| 1326 __ lw(T0, Address(SP, 0 * kWordSize)); | 1326 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1327 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); | 1327 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); |
| 1328 | 1328 |
| 1329 __ cvtwd(F2, D0); | 1329 __ cvtwd(F2, D0); |
| 1330 __ mfc1(V0, F2); | 1330 __ mfc1(V0, F2); |
| 1331 | 1331 |
| 1332 // Overflow is signaled with minint. | 1332 // Overflow is signaled with minint. |
| 1333 Label fall_through; | 1333 Label fall_through; |
| 1334 // Check for overflow and that it fits into Smi. | 1334 // Check for overflow and that it fits into Smi. |
| 1335 __ LoadImmediate(TMP, 0xC0000000); | 1335 __ LoadImmediate(TMP, 0xC0000000); |
| 1336 __ subu(CMPRES, V0, TMP); | 1336 __ subu(CMPRES1, V0, TMP); |
| 1337 __ bltz(CMPRES, &fall_through); | 1337 __ bltz(CMPRES1, &fall_through); |
| 1338 __ Ret(); | 1338 __ Ret(); |
| 1339 __ delay_slot()->SmiTag(V0); | 1339 __ delay_slot()->SmiTag(V0); |
| 1340 __ Bind(&fall_through); | 1340 __ Bind(&fall_through); |
| 1341 } | 1341 } |
| 1342 | 1342 |
| 1343 | 1343 |
| 1344 void Intrinsifier::Math_sqrt(Assembler* assembler) { | 1344 void Intrinsifier::Math_sqrt(Assembler* assembler) { |
| 1345 Label fall_through, is_smi, double_op; | 1345 Label fall_through, is_smi, double_op; |
| 1346 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1346 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1347 // Argument is double and is in T0. | 1347 // Argument is double and is in T0. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1452 } | 1452 } |
| 1453 | 1453 |
| 1454 | 1454 |
| 1455 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1455 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { |
| 1456 Label fall_through, try_two_byte_string; | 1456 Label fall_through, try_two_byte_string; |
| 1457 | 1457 |
| 1458 __ lw(T1, Address(SP, 0 * kWordSize)); // Index. | 1458 __ lw(T1, Address(SP, 0 * kWordSize)); // Index. |
| 1459 __ lw(T0, Address(SP, 1 * kWordSize)); // String. | 1459 __ lw(T0, Address(SP, 1 * kWordSize)); // String. |
| 1460 | 1460 |
| 1461 // Checks. | 1461 // Checks. |
| 1462 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 1462 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 1463 __ bne(T1, ZR, &fall_through); // Index is not a Smi. | 1463 __ bne(T1, ZR, &fall_through); // Index is not a Smi. |
| 1464 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check. | 1464 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check. |
| 1465 // Runtime throws exception. | 1465 // Runtime throws exception. |
| 1466 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); | 1466 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); |
| 1467 __ LoadClassId(CMPRES1, T0); // Class ID check. | 1467 __ LoadClassId(CMPRES1, T0); // Class ID check. |
| 1468 __ BranchNotEqual(CMPRES1, kOneByteStringCid, &try_two_byte_string); | 1468 __ BranchNotEqual(CMPRES1, kOneByteStringCid, &try_two_byte_string); |
| 1469 | 1469 |
| 1470 // Grab byte and return. | 1470 // Grab byte and return. |
| 1471 __ SmiUntag(T1); | 1471 __ SmiUntag(T1); |
| 1472 __ addu(T2, T0, T1); | 1472 __ addu(T2, T0, T1); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1583 __ LoadImmediate(TMP, ~(kObjectAlignment - 1)); | 1583 __ LoadImmediate(TMP, ~(kObjectAlignment - 1)); |
| 1584 __ and_(length_reg, length_reg, TMP); | 1584 __ and_(length_reg, length_reg, TMP); |
| 1585 | 1585 |
| 1586 Isolate* isolate = Isolate::Current(); | 1586 Isolate* isolate = Isolate::Current(); |
| 1587 Heap* heap = isolate->heap(); | 1587 Heap* heap = isolate->heap(); |
| 1588 | 1588 |
| 1589 __ LoadImmediate(T3, heap->TopAddress()); | 1589 __ LoadImmediate(T3, heap->TopAddress()); |
| 1590 __ lw(V0, Address(T3, 0)); | 1590 __ lw(V0, Address(T3, 0)); |
| 1591 | 1591 |
| 1592 // length_reg: allocation size. | 1592 // length_reg: allocation size. |
| 1593 __ AdduDetectOverflow(T1, V0, length_reg, CMPRES); | 1593 __ AdduDetectOverflow(T1, V0, length_reg, CMPRES1); |
| 1594 __ bltz(CMPRES, failure); // Fail on overflow. | 1594 __ bltz(CMPRES1, failure); // Fail on overflow. |
| 1595 | 1595 |
| 1596 // Check if the allocation fits into the remaining space. | 1596 // Check if the allocation fits into the remaining space. |
| 1597 // V0: potential new object start. | 1597 // V0: potential new object start. |
| 1598 // T1: potential next object start. | 1598 // T1: potential next object start. |
| 1599 // T2: allocation size. | 1599 // T2: allocation size. |
| 1600 // T3: heap->TopAddress(). | 1600 // T3: heap->TopAddress(). |
| 1601 __ LoadImmediate(T4, heap->EndAddress()); | 1601 __ LoadImmediate(T4, heap->EndAddress()); |
| 1602 __ lw(T4, Address(T4, 0)); | 1602 __ lw(T4, Address(T4, 0)); |
| 1603 __ BranchUnsignedGreaterEqual(T1, T4, failure); | 1603 __ BranchUnsignedGreaterEqual(T1, T4, failure); |
| 1604 | 1604 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1619 | 1619 |
| 1620 __ BranchUnsignedGreater(T2, RawObject::SizeTag::kMaxSizeTag, &overflow); | 1620 __ BranchUnsignedGreater(T2, RawObject::SizeTag::kMaxSizeTag, &overflow); |
| 1621 __ b(&done); | 1621 __ b(&done); |
| 1622 __ delay_slot()->sll(T2, T2, shift); | 1622 __ delay_slot()->sll(T2, T2, shift); |
| 1623 __ Bind(&overflow); | 1623 __ Bind(&overflow); |
| 1624 __ mov(T2, ZR); | 1624 __ mov(T2, ZR); |
| 1625 __ Bind(&done); | 1625 __ Bind(&done); |
| 1626 | 1626 |
| 1627 // Get the class index and insert it into the tags. | 1627 // Get the class index and insert it into the tags. |
| 1628 // T2: size and bit tags. | 1628 // T2: size and bit tags. |
| 1629 __ LoadImmediate(TMP1, RawObject::ClassIdTag::encode(cls.id())); | 1629 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cls.id())); |
| 1630 __ or_(T2, T2, TMP1); | 1630 __ or_(T2, T2, TMP); |
| 1631 __ sw(T2, FieldAddress(V0, String::tags_offset())); // Store tags. | 1631 __ sw(T2, FieldAddress(V0, String::tags_offset())); // Store tags. |
| 1632 } | 1632 } |
| 1633 | 1633 |
| 1634 // Set the length field using the saved length (T6). | 1634 // Set the length field using the saved length (T6). |
| 1635 __ StoreIntoObjectNoBarrier(V0, | 1635 __ StoreIntoObjectNoBarrier(V0, |
| 1636 FieldAddress(V0, String::length_offset()), | 1636 FieldAddress(V0, String::length_offset()), |
| 1637 T6); | 1637 T6); |
| 1638 // Clear hash. | 1638 // Clear hash. |
| 1639 __ b(ok); | 1639 __ b(ok); |
| 1640 __ delay_slot()->sw(ZR, FieldAddress(V0, String::hash_offset())); | 1640 __ delay_slot()->sw(ZR, FieldAddress(V0, String::hash_offset())); |
| 1641 } | 1641 } |
| 1642 | 1642 |
| 1643 | 1643 |
| 1644 // Arg0: OneByteString (receiver). | 1644 // Arg0: OneByteString (receiver). |
| 1645 // Arg1: Start index as Smi. | 1645 // Arg1: Start index as Smi. |
| 1646 // Arg2: End index as Smi. | 1646 // Arg2: End index as Smi. |
| 1647 // The indexes must be valid. | 1647 // The indexes must be valid. |
| 1648 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 1648 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
| 1649 const intptr_t kStringOffset = 2 * kWordSize; | 1649 const intptr_t kStringOffset = 2 * kWordSize; |
| 1650 const intptr_t kStartIndexOffset = 1 * kWordSize; | 1650 const intptr_t kStartIndexOffset = 1 * kWordSize; |
| 1651 const intptr_t kEndIndexOffset = 0 * kWordSize; | 1651 const intptr_t kEndIndexOffset = 0 * kWordSize; |
| 1652 Label fall_through, ok; | 1652 Label fall_through, ok; |
| 1653 | 1653 |
| 1654 __ lw(T2, Address(SP, kEndIndexOffset)); | 1654 __ lw(T2, Address(SP, kEndIndexOffset)); |
| 1655 __ lw(TMP, Address(SP, kStartIndexOffset)); | 1655 __ lw(TMP, Address(SP, kStartIndexOffset)); |
| 1656 __ or_(CMPRES, T2, TMP); | 1656 __ or_(CMPRES1, T2, TMP); |
| 1657 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); | 1657 __ andi(CMPRES1, CMPRES1, Immediate(kSmiTagMask)); |
| 1658 __ bne(CMPRES, ZR, &fall_through); // 'start', 'end' not Smi. | 1658 __ bne(CMPRES1, ZR, &fall_through); // 'start', 'end' not Smi. |
| 1659 | 1659 |
| 1660 __ subu(T2, T2, TMP); | 1660 __ subu(T2, T2, TMP); |
| 1661 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 1661 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 1662 __ Bind(&ok); | 1662 __ Bind(&ok); |
| 1663 // V0: new string as tagged pointer. | 1663 // V0: new string as tagged pointer. |
| 1664 // Copy string. | 1664 // Copy string. |
| 1665 __ lw(T3, Address(SP, kStringOffset)); | 1665 __ lw(T3, Address(SP, kStringOffset)); |
| 1666 __ lw(T1, Address(SP, kStartIndexOffset)); | 1666 __ lw(T1, Address(SP, kStartIndexOffset)); |
| 1667 __ SmiUntag(T1); | 1667 __ SmiUntag(T1); |
| 1668 __ addu(T3, T3, T1); | 1668 __ addu(T3, T3, T1); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1727 // TODO(srdjan): Add combinations (one-byte/two-byte/external strings). | 1727 // TODO(srdjan): Add combinations (one-byte/two-byte/external strings). |
| 1728 void StringEquality(Assembler* assembler, intptr_t string_cid) { | 1728 void StringEquality(Assembler* assembler, intptr_t string_cid) { |
| 1729 Label fall_through, is_true, is_false, loop; | 1729 Label fall_through, is_true, is_false, loop; |
| 1730 __ lw(T0, Address(SP, 1 * kWordSize)); // This. | 1730 __ lw(T0, Address(SP, 1 * kWordSize)); // This. |
| 1731 __ lw(T1, Address(SP, 0 * kWordSize)); // Other. | 1731 __ lw(T1, Address(SP, 0 * kWordSize)); // Other. |
| 1732 | 1732 |
| 1733 // Are identical? | 1733 // Are identical? |
| 1734 __ beq(T0, T1, &is_true); | 1734 __ beq(T0, T1, &is_true); |
| 1735 | 1735 |
| 1736 // Is other OneByteString? | 1736 // Is other OneByteString? |
| 1737 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 1737 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 1738 __ beq(CMPRES, ZR, &fall_through); // Other is Smi. | 1738 __ beq(CMPRES1, ZR, &fall_through); // Other is Smi. |
| 1739 __ LoadClassId(CMPRES1, T1); // Class ID check. | 1739 __ LoadClassId(CMPRES1, T1); // Class ID check. |
| 1740 __ BranchNotEqual(CMPRES1, string_cid, &fall_through); | 1740 __ BranchNotEqual(CMPRES1, string_cid, &fall_through); |
| 1741 | 1741 |
| 1742 // Have same length? | 1742 // Have same length? |
| 1743 __ lw(T2, FieldAddress(T0, String::length_offset())); | 1743 __ lw(T2, FieldAddress(T0, String::length_offset())); |
| 1744 __ lw(T3, FieldAddress(T1, String::length_offset())); | 1744 __ lw(T3, FieldAddress(T1, String::length_offset())); |
| 1745 __ bne(T2, T3, &is_false); | 1745 __ bne(T2, T3, &is_false); |
| 1746 | 1746 |
| 1747 // Check contents, no fall-through possible. | 1747 // Check contents, no fall-through possible. |
| 1748 ASSERT((string_cid == kOneByteStringCid) || | 1748 ASSERT((string_cid == kOneByteStringCid) || |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1783 } | 1783 } |
| 1784 | 1784 |
| 1785 | 1785 |
| 1786 void Intrinsifier::TwoByteString_equality(Assembler* assembler) { | 1786 void Intrinsifier::TwoByteString_equality(Assembler* assembler) { |
| 1787 StringEquality(assembler, kTwoByteStringCid); | 1787 StringEquality(assembler, kTwoByteStringCid); |
| 1788 } | 1788 } |
| 1789 | 1789 |
| 1790 } // namespace dart | 1790 } // namespace dart |
| 1791 | 1791 |
| 1792 #endif // defined TARGET_ARCH_MIPS | 1792 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |