| 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 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { | 23 void Intrinsifier::ObjectArray_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 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 __ Bind(&init_loop); | 123 __ Bind(&init_loop); |
| 124 __ BranchUnsignedGreaterEqual(T2, T1, &done); | 124 __ BranchUnsignedGreaterEqual(T2, T1, &done); |
| 125 __ sw(T7, Address(T2, 0)); | 125 __ sw(T7, Address(T2, 0)); |
| 126 __ b(&init_loop); | 126 __ b(&init_loop); |
| 127 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); | 127 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); |
| 128 __ Bind(&done); | 128 __ Bind(&done); |
| 129 | 129 |
| 130 __ Ret(); // Returns the newly allocated object in V0. | 130 __ Ret(); // Returns the newly allocated object in V0. |
| 131 __ delay_slot()->mov(V0, T0); | 131 __ delay_slot()->mov(V0, T0); |
| 132 __ Bind(&fall_through); | 132 __ Bind(&fall_through); |
| 133 return false; | |
| 134 } | 133 } |
| 135 | 134 |
| 136 | 135 |
| 137 bool Intrinsifier::Array_getLength(Assembler* assembler) { | 136 void Intrinsifier::Array_getLength(Assembler* assembler) { |
| 138 __ lw(V0, Address(SP, 0 * kWordSize)); | 137 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 139 __ Ret(); | 138 __ Ret(); |
| 140 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); | 139 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); |
| 141 return true; | |
| 142 } | 140 } |
| 143 | 141 |
| 144 | 142 |
| 145 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { | 143 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { |
| 146 return Array_getLength(assembler); | 144 return Array_getLength(assembler); |
| 147 } | 145 } |
| 148 | 146 |
| 149 | 147 |
| 150 bool Intrinsifier::Array_getIndexed(Assembler* assembler) { | 148 void Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 151 Label fall_through; | 149 Label fall_through; |
| 152 | 150 |
| 153 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index | 151 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index |
| 154 | 152 |
| 155 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 153 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 156 __ 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 |
| 157 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array | 155 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array |
| 158 | 156 |
| 159 // range check | 157 // range check |
| 160 __ lw(T2, FieldAddress(T1, Array::length_offset())); | 158 __ lw(T2, FieldAddress(T1, Array::length_offset())); |
| 161 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 159 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 162 | 160 |
| 163 ASSERT(kSmiTagShift == 1); | 161 ASSERT(kSmiTagShift == 1); |
| 164 // array element at T1 + T0*2 + Array::data_offset - 1 | 162 // array element at T1 + T0*2 + Array::data_offset - 1 |
| 165 __ sll(T2, T0, 1); | 163 __ sll(T2, T0, 1); |
| 166 __ addu(T2, T1, T2); | 164 __ addu(T2, T1, T2); |
| 167 __ Ret(); | 165 __ Ret(); |
| 168 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); | 166 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); |
| 169 __ Bind(&fall_through); | 167 __ Bind(&fall_through); |
| 170 return false; | |
| 171 } | 168 } |
| 172 | 169 |
| 173 | 170 |
| 174 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { | 171 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { |
| 175 return Array_getIndexed(assembler); | 172 return Array_getIndexed(assembler); |
| 176 } | 173 } |
| 177 | 174 |
| 178 | 175 |
| 179 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 176 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 180 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 177 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 181 const Class& cls = Class::Handle( | 178 const Class& cls = Class::Handle( |
| 182 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); | 179 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); |
| 183 ASSERT(!cls.IsNull()); | 180 ASSERT(!cls.IsNull()); |
| 184 ASSERT(cls.HasTypeArguments()); | 181 ASSERT(cls.HasTypeArguments()); |
| 185 ASSERT(cls.NumTypeArguments() == 1); | 182 ASSERT(cls.NumTypeArguments() == 1); |
| 186 const intptr_t field_offset = cls.type_arguments_field_offset(); | 183 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 187 ASSERT(field_offset != Class::kNoTypeArguments); | 184 ASSERT(field_offset != Class::kNoTypeArguments); |
| 188 return field_offset; | 185 return field_offset; |
| 189 } | 186 } |
| 190 | 187 |
| 191 | 188 |
| 192 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 189 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
| 193 // update. Array length is always a Smi. | 190 // update. Array length is always a Smi. |
| 194 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { | 191 void Intrinsifier::Array_setIndexed(Assembler* assembler) { |
| 195 Label fall_through; | 192 Label fall_through; |
| 196 | 193 |
| 197 if (FLAG_enable_type_checks) { | 194 if (FLAG_enable_type_checks) { |
| 198 const intptr_t type_args_field_offset = | 195 const intptr_t type_args_field_offset = |
| 199 ComputeObjectArrayTypeArgumentsOffset(); | 196 ComputeObjectArrayTypeArgumentsOffset(); |
| 200 // Inline simple tests (Smi, null), fallthrough if not positive. | 197 // Inline simple tests (Smi, null), fallthrough if not positive. |
| 201 Label checked_ok; | 198 Label checked_ok; |
| 202 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 199 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 203 | 200 |
| 204 // Null value is valid for any type. | 201 // Null value is valid for any type. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 ASSERT(kSmiTagShift == 1); | 240 ASSERT(kSmiTagShift == 1); |
| 244 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 241 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 245 __ sll(T1, T1, 1); // T1 is Smi. | 242 __ sll(T1, T1, 1); // T1 is Smi. |
| 246 __ addu(T1, T0, T1); | 243 __ addu(T1, T0, T1); |
| 247 __ StoreIntoObject(T0, | 244 __ StoreIntoObject(T0, |
| 248 FieldAddress(T1, Array::data_offset()), | 245 FieldAddress(T1, Array::data_offset()), |
| 249 T2); | 246 T2); |
| 250 // Caller is responsible for preserving the value if necessary. | 247 // Caller is responsible for preserving the value if necessary. |
| 251 __ Ret(); | 248 __ Ret(); |
| 252 __ Bind(&fall_through); | 249 __ Bind(&fall_through); |
| 253 return false; | |
| 254 } | 250 } |
| 255 | 251 |
| 256 | 252 |
| 257 // Allocate a GrowableObjectArray using the backing array specified. | 253 // Allocate a GrowableObjectArray using the backing array specified. |
| 258 // On stack: type argument (+1), data (+0). | 254 // On stack: type argument (+1), data (+0). |
| 259 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 255 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 260 // The newly allocated object is returned in V0. | 256 // The newly allocated object is returned in V0. |
| 261 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 257 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 262 const intptr_t kArrayOffset = 0 * kWordSize; | 258 const intptr_t kArrayOffset = 0 * kWordSize; |
| 263 Label fall_through; | 259 Label fall_through; |
| 264 | 260 |
| 265 // 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 |
| 266 // and is computed as: | 262 // and is computed as: |
| 267 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 263 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| 268 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); | 264 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); |
| 269 | 265 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 V0, | 307 V0, |
| 312 FieldAddress(V0, GrowableObjectArray::type_arguments_offset()), | 308 FieldAddress(V0, GrowableObjectArray::type_arguments_offset()), |
| 313 T1); | 309 T1); |
| 314 | 310 |
| 315 // Set the length field in the growable array object to 0. | 311 // Set the length field in the growable array object to 0. |
| 316 __ Ret(); // Returns the newly allocated object in V0. | 312 __ Ret(); // Returns the newly allocated object in V0. |
| 317 __ delay_slot()->sw(ZR, | 313 __ delay_slot()->sw(ZR, |
| 318 FieldAddress(V0, GrowableObjectArray::length_offset())); | 314 FieldAddress(V0, GrowableObjectArray::length_offset())); |
| 319 | 315 |
| 320 __ Bind(&fall_through); | 316 __ Bind(&fall_through); |
| 321 return false; | |
| 322 } | 317 } |
| 323 | 318 |
| 324 | 319 |
| 325 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 320 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { |
| 326 __ lw(V0, Address(SP, 0 * kWordSize)); | 321 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 327 __ Ret(); | 322 __ Ret(); |
| 328 __ delay_slot()->lw(V0, | 323 __ delay_slot()->lw(V0, |
| 329 FieldAddress(V0, GrowableObjectArray::length_offset())); | 324 FieldAddress(V0, GrowableObjectArray::length_offset())); |
| 330 return true; | |
| 331 } | 325 } |
| 332 | 326 |
| 333 | 327 |
| 334 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 328 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { |
| 335 __ lw(V0, Address(SP, 0 * kWordSize)); | 329 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 336 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset())); | 330 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset())); |
| 337 __ Ret(); | 331 __ Ret(); |
| 338 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); | 332 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); |
| 339 return true; | |
| 340 } | 333 } |
| 341 | 334 |
| 342 | 335 |
| 343 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 336 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { |
| 344 Label fall_through; | 337 Label fall_through; |
| 345 | 338 |
| 346 __ lw(T0, Address(SP, 0 * kWordSize)); // Index | 339 __ lw(T0, Address(SP, 0 * kWordSize)); // Index |
| 347 | 340 |
| 348 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 341 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 349 __ 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 |
| 350 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array | 343 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array |
| 351 | 344 |
| 352 // range check | 345 // range check |
| 353 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); | 346 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); |
| 354 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 347 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 355 | 348 |
| 356 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data | 349 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data |
| 357 | 350 |
| 358 ASSERT(kSmiTagShift == 1); | 351 ASSERT(kSmiTagShift == 1); |
| 359 // array element at T2 + T0 * 2 + Array::data_offset - 1 | 352 // array element at T2 + T0 * 2 + Array::data_offset - 1 |
| 360 __ sll(T3, T0, 1); | 353 __ sll(T3, T0, 1); |
| 361 __ addu(T2, T2, T3); | 354 __ addu(T2, T2, T3); |
| 362 __ Ret(); | 355 __ Ret(); |
| 363 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); | 356 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); |
| 364 __ Bind(&fall_through); | 357 __ Bind(&fall_through); |
| 365 return false; | |
| 366 } | 358 } |
| 367 | 359 |
| 368 | 360 |
| 369 // Set value into growable object array at specified index. | 361 // Set value into growable object array at specified index. |
| 370 // On stack: growable array (+2), index (+1), value (+0). | 362 // On stack: growable array (+2), index (+1), value (+0). |
| 371 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 363 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { |
| 372 if (FLAG_enable_type_checks) { | 364 if (FLAG_enable_type_checks) { |
| 373 return false; | 365 return; |
| 374 } | 366 } |
| 375 Label fall_through; | 367 Label fall_through; |
| 376 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. | 368 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. |
| 377 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 369 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); |
| 378 __ bne(CMPRES, ZR, &fall_through); // Non-smi index. | 370 __ bne(CMPRES, ZR, &fall_through); // Non-smi index. |
| 379 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. | 371 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 380 // Range check using _length field. | 372 // Range check using _length field. |
| 381 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); | 373 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 382 // Runtime throws exception. | 374 // Runtime throws exception. |
| 383 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); | 375 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); |
| 384 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. | 376 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. |
| 385 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 377 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 386 // Note that T1 is Smi, i.e, times 2. | 378 // Note that T1 is Smi, i.e, times 2. |
| 387 ASSERT(kSmiTagShift == 1); | 379 ASSERT(kSmiTagShift == 1); |
| 388 __ sll(T1, T1, 1); | 380 __ sll(T1, T1, 1); |
| 389 __ addu(T1, T0, T1); | 381 __ addu(T1, T0, T1); |
| 390 __ StoreIntoObject(T0, | 382 __ StoreIntoObject(T0, |
| 391 FieldAddress(T1, Array::data_offset()), | 383 FieldAddress(T1, Array::data_offset()), |
| 392 T2); | 384 T2); |
| 393 __ Ret(); | 385 __ Ret(); |
| 394 __ Bind(&fall_through); | 386 __ Bind(&fall_through); |
| 395 return false; | |
| 396 } | 387 } |
| 397 | 388 |
| 398 | 389 |
| 399 // Set length of growable object array. The length cannot | 390 // Set length of growable object array. The length cannot |
| 400 // be greater than the length of the data container. | 391 // be greater than the length of the data container. |
| 401 // On stack: growable array (+1), length (+0). | 392 // On stack: growable array (+1), length (+0). |
| 402 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 393 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { |
| 403 Label fall_through; | 394 Label fall_through; |
| 404 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. | 395 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. |
| 405 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 396 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); |
| 406 __ bne(CMPRES, ZR, &fall_through); // Non-smi length. | 397 __ bne(CMPRES, ZR, &fall_through); // Non-smi length. |
| 407 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 398 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 408 __ Ret(); | 399 __ Ret(); |
| 409 __ delay_slot()->sw(T1, | 400 __ delay_slot()->sw(T1, |
| 410 FieldAddress(T0, GrowableObjectArray::length_offset())); | 401 FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 411 __ Bind(&fall_through); | 402 __ Bind(&fall_through); |
| 412 return false; | |
| 413 } | 403 } |
| 414 | 404 |
| 415 | 405 |
| 416 // Set data of growable object array. | 406 // Set data of growable object array. |
| 417 // On stack: growable array (+1), data (+0). | 407 // On stack: growable array (+1), data (+0). |
| 418 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 408 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { |
| 419 if (FLAG_enable_type_checks) { | 409 if (FLAG_enable_type_checks) { |
| 420 return false; | 410 return; |
| 421 } | 411 } |
| 422 Label fall_through; | 412 Label fall_through; |
| 423 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. | 413 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. |
| 424 // Check that data is an ObjectArray. | 414 // Check that data is an ObjectArray. |
| 425 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 415 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); |
| 426 __ beq(CMPRES, ZR, &fall_through); // Data is Smi. | 416 __ beq(CMPRES, ZR, &fall_through); // Data is Smi. |
| 427 __ LoadClassId(CMPRES1, T1); | 417 __ LoadClassId(CMPRES1, T1); |
| 428 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); | 418 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); |
| 429 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 419 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 430 __ StoreIntoObject(T0, | 420 __ StoreIntoObject(T0, |
| 431 FieldAddress(T0, GrowableObjectArray::data_offset()), | 421 FieldAddress(T0, GrowableObjectArray::data_offset()), |
| 432 T1); | 422 T1); |
| 433 __ Ret(); | 423 __ Ret(); |
| 434 __ Bind(&fall_through); | 424 __ Bind(&fall_through); |
| 435 return false; | |
| 436 } | 425 } |
| 437 | 426 |
| 438 | 427 |
| 439 // 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 |
| 440 // call into regular code. | 429 // call into regular code. |
| 441 // On stack: growable array (+1), value (+0). | 430 // On stack: growable array (+1), value (+0). |
| 442 bool Intrinsifier::GrowableArray_add(Assembler* assembler) { | 431 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
| 443 // In checked mode we need to type-check the incoming argument. | 432 // In checked mode we need to type-check the incoming argument. |
| 444 if (FLAG_enable_type_checks) return false; | 433 if (FLAG_enable_type_checks) return; |
| 445 Label fall_through; | 434 Label fall_through; |
| 446 __ lw(T0, Address(SP, 1 * kWordSize)); // Array. | 435 __ lw(T0, Address(SP, 1 * kWordSize)); // Array. |
| 447 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset())); | 436 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 448 // T1: length. | 437 // T1: length. |
| 449 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset())); | 438 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset())); |
| 450 // T2: data. | 439 // T2: data. |
| 451 __ lw(T3, FieldAddress(T2, Array::length_offset())); | 440 __ lw(T3, FieldAddress(T2, Array::length_offset())); |
| 452 // Compare length with capacity. | 441 // Compare length with capacity. |
| 453 // T3: capacity. | 442 // T3: capacity. |
| 454 __ beq(T1, T3, &fall_through); // Must grow data. | 443 __ beq(T1, T3, &fall_through); // Must grow data. |
| 455 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1)); | 444 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1)); |
| 456 // len = len + 1; | 445 // len = len + 1; |
| 457 __ addiu(T3, T1, Immediate(value_one)); | 446 __ addiu(T3, T1, Immediate(value_one)); |
| 458 __ sw(T3, FieldAddress(T0, GrowableObjectArray::length_offset())); | 447 __ sw(T3, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 459 __ lw(T0, Address(SP, 0 * kWordSize)); // Value. | 448 __ lw(T0, Address(SP, 0 * kWordSize)); // Value. |
| 460 ASSERT(kSmiTagShift == 1); | 449 ASSERT(kSmiTagShift == 1); |
| 461 __ sll(T1, T1, 1); | 450 __ sll(T1, T1, 1); |
| 462 __ addu(T1, T2, T1); | 451 __ addu(T1, T2, T1); |
| 463 __ StoreIntoObject(T2, | 452 __ StoreIntoObject(T2, |
| 464 FieldAddress(T1, Array::data_offset()), | 453 FieldAddress(T1, Array::data_offset()), |
| 465 T0); | 454 T0); |
| 466 __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null())); | 455 __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null())); |
| 467 __ Ret(); | 456 __ Ret(); |
| 468 __ delay_slot()->mov(V0, T7); | 457 __ delay_slot()->mov(V0, T7); |
| 469 __ Bind(&fall_through); | 458 __ Bind(&fall_through); |
| 470 return false; | |
| 471 } | 459 } |
| 472 | 460 |
| 473 | 461 |
| 474 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ | 462 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ |
| 475 Label fall_through; \ | 463 Label fall_through; \ |
| 476 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ | 464 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ |
| 477 __ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ | 465 __ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ |
| 478 /* Check that length is a positive Smi. */ \ | 466 /* Check that length is a positive Smi. */ \ |
| 479 /* T2: requested array length argument. */ \ | 467 /* T2: requested array length argument. */ \ |
| 480 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); \ | 468 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); \ |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 __ sw(ZR, Address(T2, 0)); \ | 540 __ sw(ZR, Address(T2, 0)); \ |
| 553 __ b(&init_loop); \ | 541 __ b(&init_loop); \ |
| 554 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); \ | 542 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); \ |
| 555 __ Bind(&done); \ | 543 __ Bind(&done); \ |
| 556 \ | 544 \ |
| 557 __ Ret(); \ | 545 __ Ret(); \ |
| 558 __ Bind(&fall_through); \ | 546 __ Bind(&fall_through); \ |
| 559 | 547 |
| 560 | 548 |
| 561 // Gets the length of a TypedData. | 549 // Gets the length of a TypedData. |
| 562 bool Intrinsifier::TypedData_getLength(Assembler* assembler) { | 550 void Intrinsifier::TypedData_getLength(Assembler* assembler) { |
| 563 __ lw(T0, Address(SP, 0 * kWordSize)); | 551 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 564 __ Ret(); | 552 __ Ret(); |
| 565 __ delay_slot()->lw(V0, FieldAddress(T0, TypedData::length_offset())); | 553 __ delay_slot()->lw(V0, FieldAddress(T0, TypedData::length_offset())); |
| 566 return true; | |
| 567 } | 554 } |
| 568 | 555 |
| 569 | 556 |
| 570 static int GetScaleFactor(intptr_t size) { | 557 static int GetScaleFactor(intptr_t size) { |
| 571 switch (size) { | 558 switch (size) { |
| 572 case 1: return 0; | 559 case 1: return 0; |
| 573 case 2: return 1; | 560 case 2: return 1; |
| 574 case 4: return 2; | 561 case 4: return 2; |
| 575 case 8: return 3; | 562 case 8: return 3; |
| 576 case 16: return 4; | 563 case 16: return 4; |
| 577 } | 564 } |
| 578 UNREACHABLE(); | 565 UNREACHABLE(); |
| 579 return -1; | 566 return -1; |
| 580 }; | 567 }; |
| 581 | 568 |
| 582 | 569 |
| 583 #define TYPED_DATA_ALLOCATOR(clazz) \ | 570 #define TYPED_DATA_ALLOCATOR(clazz) \ |
| 584 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ | 571 void Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ |
| 585 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 572 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 586 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 573 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 587 int shift = GetScaleFactor(size); \ | 574 int shift = GetScaleFactor(size); \ |
| 588 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ | 575 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ |
| 589 return false; \ | |
| 590 } \ | 576 } \ |
| 591 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ | 577 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ |
| 592 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 578 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 593 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 579 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 594 int shift = GetScaleFactor(size); \ | 580 int shift = GetScaleFactor(size); \ |
| 595 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ | 581 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ |
| 596 return false; \ | |
| 597 } | 582 } |
| 598 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 583 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
| 599 #undef TYPED_DATA_ALLOCATOR | 584 #undef TYPED_DATA_ALLOCATOR |
| 600 | 585 |
| 601 | 586 |
| 602 // Loads args from stack into T0 and T1 | 587 // Loads args from stack into T0 and T1 |
| 603 // Tests if they are smis, jumps to label not_smi if not. | 588 // Tests if they are smis, jumps to label not_smi if not. |
| 604 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 589 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 605 __ lw(T0, Address(SP, 0 * kWordSize)); | 590 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 606 __ lw(T1, Address(SP, 1 * kWordSize)); | 591 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 607 __ or_(CMPRES, T0, T1); | 592 __ or_(CMPRES, T0, T1); |
| 608 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); | 593 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); |
| 609 __ bne(CMPRES, ZR, not_smi); | 594 __ bne(CMPRES, ZR, not_smi); |
| 610 return; | 595 return; |
| 611 } | 596 } |
| 612 | 597 |
| 613 | 598 |
| 614 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 599 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
| 615 Label fall_through; | 600 Label fall_through; |
| 616 | 601 |
| 617 TestBothArgumentsSmis(assembler, &fall_through); // Checks two Smis. | 602 TestBothArgumentsSmis(assembler, &fall_through); // Checks two Smis. |
| 618 __ AdduDetectOverflow(V0, T0, T1, CMPRES); // Add. | 603 __ AdduDetectOverflow(V0, T0, T1, CMPRES); // Add. |
| 619 __ bltz(CMPRES, &fall_through); // Fall through on overflow. | 604 __ bltz(CMPRES, &fall_through); // Fall through on overflow. |
| 620 __ Ret(); // Nothing in branch delay slot. | 605 __ Ret(); // Nothing in branch delay slot. |
| 621 __ Bind(&fall_through); | 606 __ Bind(&fall_through); |
| 622 return false; | |
| 623 } | 607 } |
| 624 | 608 |
| 625 | 609 |
| 626 bool Intrinsifier::Integer_add(Assembler* assembler) { | 610 void Intrinsifier::Integer_add(Assembler* assembler) { |
| 627 return Integer_addFromInteger(assembler); | 611 return Integer_addFromInteger(assembler); |
| 628 } | 612 } |
| 629 | 613 |
| 630 | 614 |
| 631 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 615 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
| 632 Label fall_through; | 616 Label fall_through; |
| 633 | 617 |
| 634 TestBothArgumentsSmis(assembler, &fall_through); | 618 TestBothArgumentsSmis(assembler, &fall_through); |
| 635 __ SubuDetectOverflow(V0, T0, T1, CMPRES); // Subtract. | 619 __ SubuDetectOverflow(V0, T0, T1, CMPRES); // Subtract. |
| 636 __ bltz(CMPRES, &fall_through); // Fall through on overflow. | 620 __ bltz(CMPRES, &fall_through); // Fall through on overflow. |
| 637 __ Ret(); | 621 __ Ret(); |
| 638 __ Bind(&fall_through); | 622 __ Bind(&fall_through); |
| 639 return false; | |
| 640 } | 623 } |
| 641 | 624 |
| 642 | 625 |
| 643 bool Intrinsifier::Integer_sub(Assembler* assembler) { | 626 void Intrinsifier::Integer_sub(Assembler* assembler) { |
| 644 Label fall_through; | 627 Label fall_through; |
| 645 | 628 |
| 646 TestBothArgumentsSmis(assembler, &fall_through); | 629 TestBothArgumentsSmis(assembler, &fall_through); |
| 647 __ SubuDetectOverflow(V0, T1, T0, CMPRES); // Subtract. | 630 __ SubuDetectOverflow(V0, T1, T0, CMPRES); // Subtract. |
| 648 __ bltz(CMPRES, &fall_through); // Fall through on overflow. | 631 __ bltz(CMPRES, &fall_through); // Fall through on overflow. |
| 649 __ Ret(); // Nothing in branch delay slot. | 632 __ Ret(); // Nothing in branch delay slot. |
| 650 __ Bind(&fall_through); | 633 __ Bind(&fall_through); |
| 651 return false; | |
| 652 } | 634 } |
| 653 | 635 |
| 654 | 636 |
| 655 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 637 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
| 656 Label fall_through; | 638 Label fall_through; |
| 657 | 639 |
| 658 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis | 640 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis |
| 659 __ SmiUntag(T0); // untags T0. only want result shifted by one | 641 __ SmiUntag(T0); // untags T0. only want result shifted by one |
| 660 | 642 |
| 661 __ mult(T0, T1); // HI:LO <- T0 * T1. | 643 __ mult(T0, T1); // HI:LO <- T0 * T1. |
| 662 __ mflo(V0); // V0 <- LO. | 644 __ mflo(V0); // V0 <- LO. |
| 663 __ mfhi(T2); // T2 <- HI. | 645 __ mfhi(T2); // T2 <- HI. |
| 664 __ sra(T3, V0, 31); // T3 <- V0 >> 31. | 646 __ sra(T3, V0, 31); // T3 <- V0 >> 31. |
| 665 __ bne(T2, T3, &fall_through); // Fall through on overflow. | 647 __ bne(T2, T3, &fall_through); // Fall through on overflow. |
| 666 __ Ret(); | 648 __ Ret(); |
| 667 __ Bind(&fall_through); | 649 __ Bind(&fall_through); |
| 668 return false; | |
| 669 } | 650 } |
| 670 | 651 |
| 671 | 652 |
| 672 bool Intrinsifier::Integer_mul(Assembler* assembler) { | 653 void Intrinsifier::Integer_mul(Assembler* assembler) { |
| 673 return Integer_mulFromInteger(assembler); | 654 return Integer_mulFromInteger(assembler); |
| 674 } | 655 } |
| 675 | 656 |
| 676 | 657 |
| 677 // Optimizations: | 658 // Optimizations: |
| 678 // - result is 0 if: | 659 // - result is 0 if: |
| 679 // - left is 0 | 660 // - left is 0 |
| 680 // - left equals right | 661 // - left equals right |
| 681 // - result is left if | 662 // - result is left if |
| 682 // - left > 0 && left < right | 663 // - left > 0 && left < right |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 | 695 |
| 715 // Implementation: | 696 // Implementation: |
| 716 // res = left % right; | 697 // res = left % right; |
| 717 // if (res < 0) { | 698 // if (res < 0) { |
| 718 // if (right < 0) { | 699 // if (right < 0) { |
| 719 // res = res - right; | 700 // res = res - right; |
| 720 // } else { | 701 // } else { |
| 721 // res = res + right; | 702 // res = res + right; |
| 722 // } | 703 // } |
| 723 // } | 704 // } |
| 724 bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 705 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
| 725 Label fall_through, subtract; | 706 Label fall_through, subtract; |
| 726 // Test arguments for smi. | 707 // Test arguments for smi. |
| 727 __ lw(T1, Address(SP, 0 * kWordSize)); | 708 __ lw(T1, Address(SP, 0 * kWordSize)); |
| 728 __ lw(T0, Address(SP, 1 * kWordSize)); | 709 __ lw(T0, Address(SP, 1 * kWordSize)); |
| 729 __ or_(CMPRES, T0, T1); | 710 __ or_(CMPRES, T0, T1); |
| 730 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); | 711 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); |
| 731 __ bne(CMPRES, ZR, &fall_through); | 712 __ bne(CMPRES, ZR, &fall_through); |
| 732 // T1: Tagged left (dividend). | 713 // T1: Tagged left (dividend). |
| 733 // T0: Tagged right (divisor). | 714 // T0: Tagged right (divisor). |
| 734 // Check if modulo by zero -> exception thrown in main function. | 715 // Check if modulo by zero -> exception thrown in main function. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 746 __ Bind(&subtract); | 727 __ Bind(&subtract); |
| 747 __ subu(V0, V0, T0); | 728 __ subu(V0, V0, T0); |
| 748 __ Ret(); | 729 __ Ret(); |
| 749 __ delay_slot()->SmiTag(V0); | 730 __ delay_slot()->SmiTag(V0); |
| 750 | 731 |
| 751 __ Bind(&done); | 732 __ Bind(&done); |
| 752 __ Ret(); | 733 __ Ret(); |
| 753 __ delay_slot()->SmiTag(V0); | 734 __ delay_slot()->SmiTag(V0); |
| 754 | 735 |
| 755 __ Bind(&fall_through); | 736 __ Bind(&fall_through); |
| 756 return false; | |
| 757 } | 737 } |
| 758 | 738 |
| 759 | 739 |
| 760 bool Intrinsifier::Integer_remainder(Assembler* assembler) { | 740 void Intrinsifier::Integer_remainder(Assembler* assembler) { |
| 761 Label fall_through; | 741 Label fall_through; |
| 762 | 742 |
| 763 TestBothArgumentsSmis(assembler, &fall_through); | 743 TestBothArgumentsSmis(assembler, &fall_through); |
| 764 // T1: Tagged left (dividend). | 744 // T1: Tagged left (dividend). |
| 765 // T0: Tagged right (divisor). | 745 // T0: Tagged right (divisor). |
| 766 // Check if modulo by zero -> exception thrown in main function. | 746 // Check if modulo by zero -> exception thrown in main function. |
| 767 __ beq(T0, ZR, &fall_through); | 747 __ beq(T0, ZR, &fall_through); |
| 768 EmitRemainderOperation(assembler); | 748 EmitRemainderOperation(assembler); |
| 769 // Untagged right in T0. Untagged remainder result in V0. | 749 // Untagged right in T0. Untagged remainder result in V0. |
| 770 | 750 |
| 771 __ Ret(); | 751 __ Ret(); |
| 772 __ delay_slot()->SmiTag(V0); | 752 __ delay_slot()->SmiTag(V0); |
| 773 | 753 |
| 774 __ Bind(&fall_through); | 754 __ Bind(&fall_through); |
| 775 return false; | |
| 776 } | 755 } |
| 777 | 756 |
| 778 | 757 |
| 779 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 758 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
| 780 Label fall_through; | 759 Label fall_through; |
| 781 | 760 |
| 782 TestBothArgumentsSmis(assembler, &fall_through); | 761 TestBothArgumentsSmis(assembler, &fall_through); |
| 783 __ beq(T0, ZR, &fall_through); // If b is 0, fall through. | 762 __ beq(T0, ZR, &fall_through); // If b is 0, fall through. |
| 784 | 763 |
| 785 __ SmiUntag(T0); | 764 __ SmiUntag(T0); |
| 786 __ SmiUntag(T1); | 765 __ SmiUntag(T1); |
| 787 __ div(T1, T0); // LO <- T1 / T0 | 766 __ div(T1, T0); // LO <- T1 / T0 |
| 788 __ mflo(V0); // V0 <- LO | 767 __ mflo(V0); // V0 <- LO |
| 789 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 768 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
| 790 // cannot tag the result. | 769 // cannot tag the result. |
| 791 __ BranchEqual(V0, 0x40000000, &fall_through); | 770 __ BranchEqual(V0, 0x40000000, &fall_through); |
| 792 __ Ret(); | 771 __ Ret(); |
| 793 __ delay_slot()->SmiTag(V0); | 772 __ delay_slot()->SmiTag(V0); |
| 794 __ Bind(&fall_through); | 773 __ Bind(&fall_through); |
| 795 return false; | |
| 796 } | 774 } |
| 797 | 775 |
| 798 | 776 |
| 799 bool Intrinsifier::Integer_negate(Assembler* assembler) { | 777 void Intrinsifier::Integer_negate(Assembler* assembler) { |
| 800 Label fall_through; | 778 Label fall_through; |
| 801 | 779 |
| 802 __ lw(T0, Address(SP, + 0 * kWordSize)); // Grabs first argument. | 780 __ lw(T0, Address(SP, + 0 * kWordSize)); // Grabs first argument. |
| 803 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); // Test for Smi. | 781 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); // Test for Smi. |
| 804 __ bne(CMPRES, ZR, &fall_through); // Fall through if not a Smi. | 782 __ bne(CMPRES, ZR, &fall_through); // Fall through if not a Smi. |
| 805 __ SubuDetectOverflow(V0, ZR, T0, CMPRES); | 783 __ SubuDetectOverflow(V0, ZR, T0, CMPRES); |
| 806 __ bltz(CMPRES, &fall_through); // There was overflow. | 784 __ bltz(CMPRES, &fall_through); // There was overflow. |
| 807 __ Ret(); | 785 __ Ret(); |
| 808 __ Bind(&fall_through); | 786 __ Bind(&fall_through); |
| 809 return false; | |
| 810 } | 787 } |
| 811 | 788 |
| 812 | 789 |
| 813 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 790 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
| 814 Label fall_through; | 791 Label fall_through; |
| 815 | 792 |
| 816 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. | 793 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. |
| 817 __ Ret(); | 794 __ Ret(); |
| 818 __ delay_slot()->and_(V0, T0, T1); | 795 __ delay_slot()->and_(V0, T0, T1); |
| 819 __ Bind(&fall_through); | 796 __ Bind(&fall_through); |
| 820 return false; | |
| 821 } | 797 } |
| 822 | 798 |
| 823 | 799 |
| 824 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { | 800 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
| 825 return Integer_bitAndFromInteger(assembler); | 801 return Integer_bitAndFromInteger(assembler); |
| 826 } | 802 } |
| 827 | 803 |
| 828 | 804 |
| 829 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { | 805 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
| 830 Label fall_through; | 806 Label fall_through; |
| 831 | 807 |
| 832 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. | 808 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. |
| 833 __ Ret(); | 809 __ Ret(); |
| 834 __ delay_slot()->or_(V0, T0, T1); | 810 __ delay_slot()->or_(V0, T0, T1); |
| 835 __ Bind(&fall_through); | 811 __ Bind(&fall_through); |
| 836 return false; | |
| 837 } | 812 } |
| 838 | 813 |
| 839 | 814 |
| 840 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { | 815 void Intrinsifier::Integer_bitOr(Assembler* assembler) { |
| 841 return Integer_bitOrFromInteger(assembler); | 816 return Integer_bitOrFromInteger(assembler); |
| 842 } | 817 } |
| 843 | 818 |
| 844 | 819 |
| 845 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 820 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
| 846 Label fall_through; | 821 Label fall_through; |
| 847 | 822 |
| 848 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. | 823 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. |
| 849 __ Ret(); | 824 __ Ret(); |
| 850 __ delay_slot()->xor_(V0, T0, T1); | 825 __ delay_slot()->xor_(V0, T0, T1); |
| 851 __ Bind(&fall_through); | 826 __ Bind(&fall_through); |
| 852 return false; | |
| 853 } | 827 } |
| 854 | 828 |
| 855 | 829 |
| 856 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { | 830 void Intrinsifier::Integer_bitXor(Assembler* assembler) { |
| 857 return Integer_bitXorFromInteger(assembler); | 831 return Integer_bitXorFromInteger(assembler); |
| 858 } | 832 } |
| 859 | 833 |
| 860 | 834 |
| 861 bool Intrinsifier::Integer_shl(Assembler* assembler) { | 835 void Intrinsifier::Integer_shl(Assembler* assembler) { |
| 862 ASSERT(kSmiTagShift == 1); | 836 ASSERT(kSmiTagShift == 1); |
| 863 ASSERT(kSmiTag == 0); | 837 ASSERT(kSmiTag == 0); |
| 864 Label fall_through, overflow; | 838 Label fall_through, overflow; |
| 865 | 839 |
| 866 TestBothArgumentsSmis(assembler, &fall_through); | 840 TestBothArgumentsSmis(assembler, &fall_through); |
| 867 __ BranchUnsignedGreater(T0, Smi::RawValue(Smi::kBits), &fall_through); | 841 __ BranchUnsignedGreater(T0, Smi::RawValue(Smi::kBits), &fall_through); |
| 868 __ SmiUntag(T0); | 842 __ SmiUntag(T0); |
| 869 | 843 |
| 870 // Check for overflow by shifting left and shifting back arithmetically. | 844 // Check for overflow by shifting left and shifting back arithmetically. |
| 871 // If the result is different from the original, there was overflow. | 845 // If the result is different from the original, there was overflow. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 898 __ sllv(T0, T1, T0); // T0 gets low bits. | 872 __ sllv(T0, T1, T0); // T0 gets low bits. |
| 899 | 873 |
| 900 const Class& mint_class = Class::Handle( | 874 const Class& mint_class = Class::Handle( |
| 901 Isolate::Current()->object_store()->mint_class()); | 875 Isolate::Current()->object_store()->mint_class()); |
| 902 __ TryAllocate(mint_class, &fall_through, V0); | 876 __ TryAllocate(mint_class, &fall_through, V0); |
| 903 | 877 |
| 904 __ sw(T0, FieldAddress(V0, Mint::value_offset())); | 878 __ sw(T0, FieldAddress(V0, Mint::value_offset())); |
| 905 __ Ret(); | 879 __ Ret(); |
| 906 __ delay_slot()->sw(T3, FieldAddress(V0, Mint::value_offset() + kWordSize)); | 880 __ delay_slot()->sw(T3, FieldAddress(V0, Mint::value_offset() + kWordSize)); |
| 907 __ Bind(&fall_through); | 881 __ Bind(&fall_through); |
| 908 return false; | |
| 909 } | 882 } |
| 910 | 883 |
| 911 | 884 |
| 912 static void Get64SmiOrMint(Assembler* assembler, | 885 static void Get64SmiOrMint(Assembler* assembler, |
| 913 Register res_hi, | 886 Register res_hi, |
| 914 Register res_lo, | 887 Register res_lo, |
| 915 Register reg, | 888 Register reg, |
| 916 Label* not_smi_or_mint) { | 889 Label* not_smi_or_mint) { |
| 917 Label not_smi, done; | 890 Label not_smi, done; |
| 918 __ andi(CMPRES, reg, Immediate(kSmiTagMask)); | 891 __ andi(CMPRES, reg, Immediate(kSmiTagMask)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 929 __ BranchNotEqual(CMPRES1, kMintCid, not_smi_or_mint); | 902 __ BranchNotEqual(CMPRES1, kMintCid, not_smi_or_mint); |
| 930 | 903 |
| 931 // Mint. | 904 // Mint. |
| 932 __ lw(res_lo, FieldAddress(reg, Mint::value_offset())); | 905 __ lw(res_lo, FieldAddress(reg, Mint::value_offset())); |
| 933 __ lw(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize)); | 906 __ lw(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize)); |
| 934 __ Bind(&done); | 907 __ Bind(&done); |
| 935 return; | 908 return; |
| 936 } | 909 } |
| 937 | 910 |
| 938 | 911 |
| 939 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { | 912 static void CompareIntegers(Assembler* assembler, Condition true_condition) { |
| 940 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; | 913 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; |
| 941 TestBothArgumentsSmis(assembler, &try_mint_smi); | 914 TestBothArgumentsSmis(assembler, &try_mint_smi); |
| 942 // T0 contains the right argument. T1 contains left argument | 915 // T0 contains the right argument. T1 contains left argument |
| 943 | 916 |
| 944 switch (true_condition) { | 917 switch (true_condition) { |
| 945 case LT: __ BranchSignedLess(T1, T0, &is_true); break; | 918 case LT: __ BranchSignedLess(T1, T0, &is_true); break; |
| 946 case LE: __ BranchSignedLessEqual(T1, T0, &is_true); break; | 919 case LE: __ BranchSignedLessEqual(T1, T0, &is_true); break; |
| 947 case GT: __ BranchSignedGreater(T1, T0, &is_true); break; | 920 case GT: __ BranchSignedGreater(T1, T0, &is_true); break; |
| 948 case GE: __ BranchSignedGreaterEqual(T1, T0, &is_true); break; | 921 case GE: __ BranchSignedGreaterEqual(T1, T0, &is_true); break; |
| 949 default: | 922 default: |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 break; | 971 break; |
| 999 } | 972 } |
| 1000 default: | 973 default: |
| 1001 UNREACHABLE(); | 974 UNREACHABLE(); |
| 1002 break; | 975 break; |
| 1003 } | 976 } |
| 1004 // Else is true. | 977 // Else is true. |
| 1005 __ b(&is_true); | 978 __ b(&is_true); |
| 1006 | 979 |
| 1007 __ Bind(&fall_through); | 980 __ Bind(&fall_through); |
| 1008 return false; | |
| 1009 } | 981 } |
| 1010 | 982 |
| 1011 | 983 |
| 1012 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { | 984 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { |
| 1013 return CompareIntegers(assembler, LT); | 985 return CompareIntegers(assembler, LT); |
| 1014 } | 986 } |
| 1015 | 987 |
| 1016 | 988 |
| 1017 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { | 989 void Intrinsifier::Integer_lessThan(Assembler* assembler) { |
| 1018 return Integer_greaterThanFromInt(assembler); | 990 return Integer_greaterThanFromInt(assembler); |
| 1019 } | 991 } |
| 1020 | 992 |
| 1021 | 993 |
| 1022 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { | 994 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { |
| 1023 return CompareIntegers(assembler, GT); | 995 return CompareIntegers(assembler, GT); |
| 1024 } | 996 } |
| 1025 | 997 |
| 1026 | 998 |
| 1027 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { | 999 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { |
| 1028 return CompareIntegers(assembler, LE); | 1000 return CompareIntegers(assembler, LE); |
| 1029 } | 1001 } |
| 1030 | 1002 |
| 1031 | 1003 |
| 1032 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { | 1004 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { |
| 1033 return CompareIntegers(assembler, GE); | 1005 return CompareIntegers(assembler, GE); |
| 1034 } | 1006 } |
| 1035 | 1007 |
| 1036 | 1008 |
| 1037 // This is called for Smi, Mint and Bigint receivers. The right argument | 1009 // This is called for Smi, Mint and Bigint receivers. The right argument |
| 1038 // can be Smi, Mint, Bigint or double. | 1010 // can be Smi, Mint, Bigint or double. |
| 1039 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 1011 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
| 1040 Label fall_through, true_label, check_for_mint; | 1012 Label fall_through, true_label, check_for_mint; |
| 1041 // For integer receiver '===' check first. | 1013 // For integer receiver '===' check first. |
| 1042 __ lw(T0, Address(SP, 0 * kWordSize)); | 1014 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1043 __ lw(T1, Address(SP, 1 * kWordSize)); | 1015 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 1044 __ beq(T0, T1, &true_label); | 1016 __ beq(T0, T1, &true_label); |
| 1045 | 1017 |
| 1046 __ or_(T2, T0, T1); | 1018 __ or_(T2, T0, T1); |
| 1047 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); | 1019 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); |
| 1048 // If T0 or T1 is not a smi do Mint checks. | 1020 // If T0 or T1 is not a smi do Mint checks. |
| 1049 __ bne(CMPRES, ZR, &check_for_mint); | 1021 __ bne(CMPRES, ZR, &check_for_mint); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1077 __ LoadClassId(CMPRES1, T1); | 1049 __ LoadClassId(CMPRES1, T1); |
| 1078 __ BranchNotEqual(CMPRES1, kMintCid, &fall_through); | 1050 __ BranchNotEqual(CMPRES1, kMintCid, &fall_through); |
| 1079 // Receiver is Mint, return false if right is Smi. | 1051 // Receiver is Mint, return false if right is Smi. |
| 1080 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1052 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 1081 __ bne(CMPRES, ZR, &fall_through); | 1053 __ bne(CMPRES, ZR, &fall_through); |
| 1082 __ LoadObject(V0, Bool::False()); | 1054 __ LoadObject(V0, Bool::False()); |
| 1083 __ Ret(); | 1055 __ Ret(); |
| 1084 // TODO(srdjan): Implement Mint == Mint comparison. | 1056 // TODO(srdjan): Implement Mint == Mint comparison. |
| 1085 | 1057 |
| 1086 __ Bind(&fall_through); | 1058 __ Bind(&fall_through); |
| 1087 return false; | |
| 1088 } | 1059 } |
| 1089 | 1060 |
| 1090 | 1061 |
| 1091 bool Intrinsifier::Integer_equal(Assembler* assembler) { | 1062 void Intrinsifier::Integer_equal(Assembler* assembler) { |
| 1092 return Integer_equalToInteger(assembler); | 1063 return Integer_equalToInteger(assembler); |
| 1093 } | 1064 } |
| 1094 | 1065 |
| 1095 | 1066 |
| 1096 bool Intrinsifier::Integer_sar(Assembler* assembler) { | 1067 void Intrinsifier::Integer_sar(Assembler* assembler) { |
| 1097 Label fall_through; | 1068 Label fall_through; |
| 1098 | 1069 |
| 1099 TestBothArgumentsSmis(assembler, &fall_through); | 1070 TestBothArgumentsSmis(assembler, &fall_through); |
| 1100 // Shift amount in T0. Value to shift in T1. | 1071 // Shift amount in T0. Value to shift in T1. |
| 1101 | 1072 |
| 1102 __ SmiUntag(T0); | 1073 __ SmiUntag(T0); |
| 1103 __ bltz(T0, &fall_through); | 1074 __ bltz(T0, &fall_through); |
| 1104 | 1075 |
| 1105 __ LoadImmediate(T2, 0x1F); | 1076 __ LoadImmediate(T2, 0x1F); |
| 1106 __ slt(CMPRES, T2, T0); // CMPRES <- 0x1F < T0 ? 1 : 0 | 1077 __ slt(CMPRES, T2, T0); // CMPRES <- 0x1F < T0 ? 1 : 0 |
| 1107 __ movn(T0, T2, CMPRES); // T0 <- 0x1F < T0 ? 0x1F : T0 | 1078 __ movn(T0, T2, CMPRES); // T0 <- 0x1F < T0 ? 0x1F : T0 |
| 1108 | 1079 |
| 1109 __ SmiUntag(T1); | 1080 __ SmiUntag(T1); |
| 1110 __ srav(V0, T1, T0); | 1081 __ srav(V0, T1, T0); |
| 1111 __ Ret(); | 1082 __ Ret(); |
| 1112 __ delay_slot()->SmiTag(V0); | 1083 __ delay_slot()->SmiTag(V0); |
| 1113 __ Bind(&fall_through); | 1084 __ Bind(&fall_through); |
| 1114 return false; | |
| 1115 } | 1085 } |
| 1116 | 1086 |
| 1117 | 1087 |
| 1118 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 1088 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
| 1119 __ lw(T0, Address(SP, 0 * kWordSize)); | 1089 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1120 __ nor(V0, T0, ZR); | 1090 __ nor(V0, T0, ZR); |
| 1121 __ Ret(); | 1091 __ Ret(); |
| 1122 __ delay_slot()->addiu(V0, V0, Immediate(-1)); // Remove inverted smi-tag. | 1092 __ delay_slot()->addiu(V0, V0, Immediate(-1)); // Remove inverted smi-tag. |
| 1123 return false; | |
| 1124 } | 1093 } |
| 1125 | 1094 |
| 1126 | 1095 |
| 1127 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1096 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 1128 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1097 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 1129 // Returns the last argument in T0. | 1098 // Returns the last argument in T0. |
| 1130 static void TestLastArgumentIsDouble(Assembler* assembler, | 1099 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 1131 Label* is_smi, | 1100 Label* is_smi, |
| 1132 Label* not_double_smi) { | 1101 Label* not_double_smi) { |
| 1133 __ lw(T0, Address(SP, 0 * kWordSize)); | 1102 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1134 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1103 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 1135 __ beq(CMPRES, ZR, is_smi); | 1104 __ beq(CMPRES, ZR, is_smi); |
| 1136 __ LoadClassId(CMPRES1, T0); | 1105 __ LoadClassId(CMPRES1, T0); |
| 1137 __ BranchNotEqual(CMPRES1, kDoubleCid, not_double_smi); | 1106 __ BranchNotEqual(CMPRES1, kDoubleCid, not_double_smi); |
| 1138 // Fall through with Double in T0. | 1107 // Fall through with Double in T0. |
| 1139 } | 1108 } |
| 1140 | 1109 |
| 1141 | 1110 |
| 1142 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 1111 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
| 1143 // type. Return true or false object in the register V0. Any NaN argument | 1112 // type. Return true or false object in the register V0. Any NaN argument |
| 1144 // returns false. Any non-double arg1 causes control flow to fall through to the | 1113 // returns false. Any non-double arg1 causes control flow to fall through to the |
| 1145 // slow case (compiled method body). | 1114 // slow case (compiled method body). |
| 1146 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { | 1115 static void CompareDoubles(Assembler* assembler, Condition true_condition) { |
| 1147 Label is_smi, double_op, no_NaN, fall_through; | 1116 Label is_smi, double_op, no_NaN, fall_through; |
| 1148 __ Comment("CompareDoubles Intrinsic"); | 1117 __ Comment("CompareDoubles Intrinsic"); |
| 1149 | 1118 |
| 1150 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1119 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1151 // Both arguments are double, right operand is in T0. | 1120 // Both arguments are double, right operand is in T0. |
| 1152 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); | 1121 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); |
| 1153 __ Bind(&double_op); | 1122 __ Bind(&double_op); |
| 1154 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument. | 1123 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument. |
| 1155 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); | 1124 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); |
| 1156 // Now, left is in D0, right is in D1. | 1125 // Now, left is in D0, right is in D1. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1183 __ Ret(); | 1152 __ Ret(); |
| 1184 | 1153 |
| 1185 | 1154 |
| 1186 __ Bind(&is_smi); | 1155 __ Bind(&is_smi); |
| 1187 __ SmiUntag(T0); | 1156 __ SmiUntag(T0); |
| 1188 __ mtc1(T0, STMP1); | 1157 __ mtc1(T0, STMP1); |
| 1189 __ cvtdw(D1, STMP1); | 1158 __ cvtdw(D1, STMP1); |
| 1190 __ b(&double_op); | 1159 __ b(&double_op); |
| 1191 | 1160 |
| 1192 __ Bind(&fall_through); | 1161 __ Bind(&fall_through); |
| 1193 return false; | |
| 1194 } | 1162 } |
| 1195 | 1163 |
| 1196 | 1164 |
| 1197 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { | 1165 void Intrinsifier::Double_greaterThan(Assembler* assembler) { |
| 1198 return CompareDoubles(assembler, GT); | 1166 return CompareDoubles(assembler, GT); |
| 1199 } | 1167 } |
| 1200 | 1168 |
| 1201 | 1169 |
| 1202 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { | 1170 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { |
| 1203 return CompareDoubles(assembler, GE); | 1171 return CompareDoubles(assembler, GE); |
| 1204 } | 1172 } |
| 1205 | 1173 |
| 1206 | 1174 |
| 1207 bool Intrinsifier::Double_lessThan(Assembler* assembler) { | 1175 void Intrinsifier::Double_lessThan(Assembler* assembler) { |
| 1208 return CompareDoubles(assembler, LT); | 1176 return CompareDoubles(assembler, LT); |
| 1209 } | 1177 } |
| 1210 | 1178 |
| 1211 | 1179 |
| 1212 bool Intrinsifier::Double_equal(Assembler* assembler) { | 1180 void Intrinsifier::Double_equal(Assembler* assembler) { |
| 1213 return CompareDoubles(assembler, EQ); | 1181 return CompareDoubles(assembler, EQ); |
| 1214 } | 1182 } |
| 1215 | 1183 |
| 1216 | 1184 |
| 1217 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { | 1185 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { |
| 1218 return CompareDoubles(assembler, LE); | 1186 return CompareDoubles(assembler, LE); |
| 1219 } | 1187 } |
| 1220 | 1188 |
| 1221 | 1189 |
| 1222 // Expects left argument to be double (receiver). Right argument is unknown. | 1190 // Expects left argument to be double (receiver). Right argument is unknown. |
| 1223 // Both arguments are on stack. | 1191 // Both arguments are on stack. |
| 1224 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 1192 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
| 1225 Label fall_through; | 1193 Label fall_through; |
| 1226 | 1194 |
| 1227 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); | 1195 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); |
| 1228 // Both arguments are double, right operand is in T0. | 1196 // Both arguments are double, right operand is in T0. |
| 1229 __ lwc1(F2, FieldAddress(T0, Double::value_offset())); | 1197 __ lwc1(F2, FieldAddress(T0, Double::value_offset())); |
| 1230 __ lwc1(F3, FieldAddress(T0, Double::value_offset() + kWordSize)); | 1198 __ lwc1(F3, FieldAddress(T0, Double::value_offset() + kWordSize)); |
| 1231 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument. | 1199 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument. |
| 1232 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); | 1200 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); |
| 1233 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); | 1201 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); |
| 1234 switch (kind) { | 1202 switch (kind) { |
| 1235 case Token::kADD: __ addd(D0, D0, D1); break; | 1203 case Token::kADD: __ addd(D0, D0, D1); break; |
| 1236 case Token::kSUB: __ subd(D0, D0, D1); break; | 1204 case Token::kSUB: __ subd(D0, D0, D1); break; |
| 1237 case Token::kMUL: __ muld(D0, D0, D1); break; | 1205 case Token::kMUL: __ muld(D0, D0, D1); break; |
| 1238 case Token::kDIV: __ divd(D0, D0, D1); break; | 1206 case Token::kDIV: __ divd(D0, D0, D1); break; |
| 1239 default: UNREACHABLE(); | 1207 default: UNREACHABLE(); |
| 1240 } | 1208 } |
| 1241 const Class& double_class = Class::Handle( | 1209 const Class& double_class = Class::Handle( |
| 1242 Isolate::Current()->object_store()->double_class()); | 1210 Isolate::Current()->object_store()->double_class()); |
| 1243 __ TryAllocate(double_class, &fall_through, V0); // Result register. | 1211 __ TryAllocate(double_class, &fall_through, V0); // Result register. |
| 1244 __ swc1(F0, FieldAddress(V0, Double::value_offset())); | 1212 __ swc1(F0, FieldAddress(V0, Double::value_offset())); |
| 1245 __ Ret(); | 1213 __ Ret(); |
| 1246 __ delay_slot()->swc1(F1, | 1214 __ delay_slot()->swc1(F1, |
| 1247 FieldAddress(V0, Double::value_offset() + kWordSize)); | 1215 FieldAddress(V0, Double::value_offset() + kWordSize)); |
| 1248 __ Bind(&fall_through); | 1216 __ Bind(&fall_through); |
| 1249 return false; | |
| 1250 } | 1217 } |
| 1251 | 1218 |
| 1252 | 1219 |
| 1253 bool Intrinsifier::Double_add(Assembler* assembler) { | 1220 void Intrinsifier::Double_add(Assembler* assembler) { |
| 1254 return DoubleArithmeticOperations(assembler, Token::kADD); | 1221 return DoubleArithmeticOperations(assembler, Token::kADD); |
| 1255 } | 1222 } |
| 1256 | 1223 |
| 1257 | 1224 |
| 1258 bool Intrinsifier::Double_mul(Assembler* assembler) { | 1225 void Intrinsifier::Double_mul(Assembler* assembler) { |
| 1259 return DoubleArithmeticOperations(assembler, Token::kMUL); | 1226 return DoubleArithmeticOperations(assembler, Token::kMUL); |
| 1260 } | 1227 } |
| 1261 | 1228 |
| 1262 | 1229 |
| 1263 bool Intrinsifier::Double_sub(Assembler* assembler) { | 1230 void Intrinsifier::Double_sub(Assembler* assembler) { |
| 1264 return DoubleArithmeticOperations(assembler, Token::kSUB); | 1231 return DoubleArithmeticOperations(assembler, Token::kSUB); |
| 1265 } | 1232 } |
| 1266 | 1233 |
| 1267 | 1234 |
| 1268 bool Intrinsifier::Double_div(Assembler* assembler) { | 1235 void Intrinsifier::Double_div(Assembler* assembler) { |
| 1269 return DoubleArithmeticOperations(assembler, Token::kDIV); | 1236 return DoubleArithmeticOperations(assembler, Token::kDIV); |
| 1270 } | 1237 } |
| 1271 | 1238 |
| 1272 | 1239 |
| 1273 // Left is double right is integer (Bigint, Mint or Smi) | 1240 // Left is double right is integer (Bigint, Mint or Smi) |
| 1274 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 1241 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 1275 Label fall_through; | 1242 Label fall_through; |
| 1276 // Only Smi-s allowed. | 1243 // Only Smi-s allowed. |
| 1277 __ lw(T0, Address(SP, 0 * kWordSize)); | 1244 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1278 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1245 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 1279 __ bne(CMPRES, ZR, &fall_through); | 1246 __ bne(CMPRES, ZR, &fall_through); |
| 1280 | 1247 |
| 1281 // Is Smi. | 1248 // Is Smi. |
| 1282 __ SmiUntag(T0); | 1249 __ SmiUntag(T0); |
| 1283 __ mtc1(T0, F4); | 1250 __ mtc1(T0, F4); |
| 1284 __ cvtdw(D1, F4); | 1251 __ cvtdw(D1, F4); |
| 1285 | 1252 |
| 1286 __ lw(T0, Address(SP, 1 * kWordSize)); | 1253 __ lw(T0, Address(SP, 1 * kWordSize)); |
| 1287 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); | 1254 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); |
| 1288 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); | 1255 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); |
| 1289 __ muld(D0, D0, D1); | 1256 __ muld(D0, D0, D1); |
| 1290 const Class& double_class = Class::Handle( | 1257 const Class& double_class = Class::Handle( |
| 1291 Isolate::Current()->object_store()->double_class()); | 1258 Isolate::Current()->object_store()->double_class()); |
| 1292 __ TryAllocate(double_class, &fall_through, V0); // Result register. | 1259 __ TryAllocate(double_class, &fall_through, V0); // Result register. |
| 1293 __ swc1(F0, FieldAddress(V0, Double::value_offset())); | 1260 __ swc1(F0, FieldAddress(V0, Double::value_offset())); |
| 1294 __ Ret(); | 1261 __ Ret(); |
| 1295 __ delay_slot()->swc1(F1, | 1262 __ delay_slot()->swc1(F1, |
| 1296 FieldAddress(V0, Double::value_offset() + kWordSize)); | 1263 FieldAddress(V0, Double::value_offset() + kWordSize)); |
| 1297 __ Bind(&fall_through); | 1264 __ Bind(&fall_through); |
| 1298 return false; | |
| 1299 } | 1265 } |
| 1300 | 1266 |
| 1301 | 1267 |
| 1302 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { | 1268 void Intrinsifier::Double_fromInteger(Assembler* assembler) { |
| 1303 Label fall_through; | 1269 Label fall_through; |
| 1304 | 1270 |
| 1305 __ lw(T0, Address(SP, 0 * kWordSize)); | 1271 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1306 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); | 1272 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 1307 __ bne(T0, ZR, &fall_through); | 1273 __ bne(T0, ZR, &fall_through); |
| 1308 | 1274 |
| 1309 // Is Smi. | 1275 // Is Smi. |
| 1310 __ SmiUntag(T0); | 1276 __ SmiUntag(T0); |
| 1311 __ mtc1(T0, F4); | 1277 __ mtc1(T0, F4); |
| 1312 __ cvtdw(D0, F4); | 1278 __ cvtdw(D0, F4); |
| 1313 const Class& double_class = Class::Handle( | 1279 const Class& double_class = Class::Handle( |
| 1314 Isolate::Current()->object_store()->double_class()); | 1280 Isolate::Current()->object_store()->double_class()); |
| 1315 __ TryAllocate(double_class, &fall_through, V0); // Result register. | 1281 __ TryAllocate(double_class, &fall_through, V0); // Result register. |
| 1316 __ swc1(F0, FieldAddress(V0, Double::value_offset())); | 1282 __ swc1(F0, FieldAddress(V0, Double::value_offset())); |
| 1317 __ Ret(); | 1283 __ Ret(); |
| 1318 __ delay_slot()->swc1(F1, | 1284 __ delay_slot()->swc1(F1, |
| 1319 FieldAddress(V0, Double::value_offset() + kWordSize)); | 1285 FieldAddress(V0, Double::value_offset() + kWordSize)); |
| 1320 __ Bind(&fall_through); | 1286 __ Bind(&fall_through); |
| 1321 return false; | |
| 1322 } | 1287 } |
| 1323 | 1288 |
| 1324 | 1289 |
| 1325 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1290 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
| 1326 Label is_true; | 1291 Label is_true; |
| 1327 | 1292 |
| 1328 __ lw(T0, Address(SP, 0 * kWordSize)); | 1293 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1329 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); | 1294 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); |
| 1330 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); | 1295 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); |
| 1331 __ cund(D0, D0); // Check for NaN. | 1296 __ cund(D0, D0); // Check for NaN. |
| 1332 __ bc1t(&is_true); | 1297 __ bc1t(&is_true); |
| 1333 __ LoadObject(V0, Bool::False()); // Return false if either is NaN. | 1298 __ LoadObject(V0, Bool::False()); // Return false if either is NaN. |
| 1334 __ Ret(); | 1299 __ Ret(); |
| 1335 __ Bind(&is_true); | 1300 __ Bind(&is_true); |
| 1336 __ LoadObject(V0, Bool::True()); | 1301 __ LoadObject(V0, Bool::True()); |
| 1337 __ Ret(); | 1302 __ Ret(); |
| 1338 return true; | |
| 1339 } | 1303 } |
| 1340 | 1304 |
| 1341 | 1305 |
| 1342 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1306 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
| 1343 Label is_false, is_true, is_zero; | 1307 Label is_false, is_true, is_zero; |
| 1344 __ lw(T0, Address(SP, 0 * kWordSize)); | 1308 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1345 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); | 1309 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); |
| 1346 | 1310 |
| 1347 __ cund(D0, D0); | 1311 __ cund(D0, D0); |
| 1348 __ bc1t(&is_false); // NaN -> false. | 1312 __ bc1t(&is_false); // NaN -> false. |
| 1349 | 1313 |
| 1350 __ LoadImmediate(D1, 0.0); | 1314 __ LoadImmediate(D1, 0.0); |
| 1351 __ ceqd(D0, D1); | 1315 __ ceqd(D0, D1); |
| 1352 __ bc1t(&is_zero); // Check for negative zero. | 1316 __ bc1t(&is_zero); // Check for negative zero. |
| 1353 | 1317 |
| 1354 __ coled(D1, D0); | 1318 __ coled(D1, D0); |
| 1355 __ bc1t(&is_false); // >= 0 -> false. | 1319 __ bc1t(&is_false); // >= 0 -> false. |
| 1356 | 1320 |
| 1357 __ Bind(&is_true); | 1321 __ Bind(&is_true); |
| 1358 __ LoadObject(V0, Bool::True()); | 1322 __ LoadObject(V0, Bool::True()); |
| 1359 __ Ret(); | 1323 __ Ret(); |
| 1360 | 1324 |
| 1361 __ Bind(&is_false); | 1325 __ Bind(&is_false); |
| 1362 __ LoadObject(V0, Bool::False()); | 1326 __ LoadObject(V0, Bool::False()); |
| 1363 __ Ret(); | 1327 __ Ret(); |
| 1364 | 1328 |
| 1365 __ Bind(&is_zero); | 1329 __ Bind(&is_zero); |
| 1366 // Check for negative zero by looking at the sign bit. | 1330 // Check for negative zero by looking at the sign bit. |
| 1367 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0. | 1331 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0. |
| 1368 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0. | 1332 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0. |
| 1369 __ andi(CMPRES, T0, Immediate(1)); // Check if the bit is set. | 1333 __ andi(CMPRES, T0, Immediate(1)); // Check if the bit is set. |
| 1370 __ bne(T0, ZR, &is_true); // Sign bit set. True. | 1334 __ bne(T0, ZR, &is_true); // Sign bit set. True. |
| 1371 __ b(&is_false); | 1335 __ b(&is_false); |
| 1372 return true; | |
| 1373 } | 1336 } |
| 1374 | 1337 |
| 1375 | 1338 |
| 1376 bool Intrinsifier::Double_toInt(Assembler* assembler) { | 1339 void Intrinsifier::Double_toInt(Assembler* assembler) { |
| 1377 __ lw(T0, Address(SP, 0 * kWordSize)); | 1340 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1378 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); | 1341 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); |
| 1379 | 1342 |
| 1380 __ cvtwd(F2, D0); | 1343 __ cvtwd(F2, D0); |
| 1381 __ mfc1(V0, F2); | 1344 __ mfc1(V0, F2); |
| 1382 | 1345 |
| 1383 // Overflow is signaled with minint. | 1346 // Overflow is signaled with minint. |
| 1384 Label fall_through; | 1347 Label fall_through; |
| 1385 // Check for overflow and that it fits into Smi. | 1348 // Check for overflow and that it fits into Smi. |
| 1386 __ LoadImmediate(TMP, 0xC0000000); | 1349 __ LoadImmediate(TMP, 0xC0000000); |
| 1387 __ subu(CMPRES, V0, TMP); | 1350 __ subu(CMPRES, V0, TMP); |
| 1388 __ bltz(CMPRES, &fall_through); | 1351 __ bltz(CMPRES, &fall_through); |
| 1389 __ Ret(); | 1352 __ Ret(); |
| 1390 __ delay_slot()->SmiTag(V0); | 1353 __ delay_slot()->SmiTag(V0); |
| 1391 __ Bind(&fall_through); | 1354 __ Bind(&fall_through); |
| 1392 return false; | |
| 1393 } | 1355 } |
| 1394 | 1356 |
| 1395 | 1357 |
| 1396 bool Intrinsifier::Math_sqrt(Assembler* assembler) { | 1358 void Intrinsifier::Math_sqrt(Assembler* assembler) { |
| 1397 Label fall_through, is_smi, double_op; | 1359 Label fall_through, is_smi, double_op; |
| 1398 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1360 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1399 // Argument is double and is in T0. | 1361 // Argument is double and is in T0. |
| 1400 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); | 1362 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); |
| 1401 __ Bind(&double_op); | 1363 __ Bind(&double_op); |
| 1402 __ sqrtd(D0, D1); | 1364 __ sqrtd(D0, D1); |
| 1403 const Class& double_class = Class::Handle( | 1365 const Class& double_class = Class::Handle( |
| 1404 Isolate::Current()->object_store()->double_class()); | 1366 Isolate::Current()->object_store()->double_class()); |
| 1405 __ TryAllocate(double_class, &fall_through, V0); // Result register. | 1367 __ TryAllocate(double_class, &fall_through, V0); // Result register. |
| 1406 __ swc1(F0, FieldAddress(V0, Double::value_offset())); | 1368 __ swc1(F0, FieldAddress(V0, Double::value_offset())); |
| 1407 __ Ret(); | 1369 __ Ret(); |
| 1408 __ delay_slot()->swc1(F1, | 1370 __ delay_slot()->swc1(F1, |
| 1409 FieldAddress(V0, Double::value_offset() + kWordSize)); | 1371 FieldAddress(V0, Double::value_offset() + kWordSize)); |
| 1410 | 1372 |
| 1411 __ Bind(&is_smi); | 1373 __ Bind(&is_smi); |
| 1412 __ SmiUntag(T0); | 1374 __ SmiUntag(T0); |
| 1413 __ mtc1(T0, F2); | 1375 __ mtc1(T0, F2); |
| 1414 __ b(&double_op); | 1376 __ b(&double_op); |
| 1415 __ delay_slot()->cvtdw(D1, F2); | 1377 __ delay_slot()->cvtdw(D1, F2); |
| 1416 __ Bind(&fall_through); | 1378 __ Bind(&fall_through); |
| 1417 return false; | |
| 1418 } | 1379 } |
| 1419 | 1380 |
| 1420 | 1381 |
| 1421 bool Intrinsifier::Math_sin(Assembler* assembler) { | 1382 void Intrinsifier::Math_sin(Assembler* assembler) { |
| 1422 return false; | |
| 1423 } | 1383 } |
| 1424 | 1384 |
| 1425 | 1385 |
| 1426 bool Intrinsifier::Math_cos(Assembler* assembler) { | 1386 void Intrinsifier::Math_cos(Assembler* assembler) { |
| 1427 return false; | |
| 1428 } | 1387 } |
| 1429 | 1388 |
| 1430 | 1389 |
| 1431 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; | 1390 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
| 1432 // _state[kSTATE_LO] = state & _MASK_32; | 1391 // _state[kSTATE_LO] = state & _MASK_32; |
| 1433 // _state[kSTATE_HI] = state >> 32; | 1392 // _state[kSTATE_HI] = state >> 32; |
| 1434 bool Intrinsifier::Random_nextState(Assembler* assembler) { | 1393 void Intrinsifier::Random_nextState(Assembler* assembler) { |
| 1435 const Library& math_lib = Library::Handle(Library::MathLibrary()); | 1394 const Library& math_lib = Library::Handle(Library::MathLibrary()); |
| 1436 ASSERT(!math_lib.IsNull()); | 1395 ASSERT(!math_lib.IsNull()); |
| 1437 const Class& random_class = Class::Handle( | 1396 const Class& random_class = Class::Handle( |
| 1438 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); | 1397 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); |
| 1439 ASSERT(!random_class.IsNull()); | 1398 ASSERT(!random_class.IsNull()); |
| 1440 const Field& state_field = Field::ZoneHandle( | 1399 const Field& state_field = Field::ZoneHandle( |
| 1441 random_class.LookupInstanceField(Symbols::_state())); | 1400 random_class.LookupInstanceField(Symbols::_state())); |
| 1442 ASSERT(!state_field.IsNull()); | 1401 ASSERT(!state_field.IsNull()); |
| 1443 const Field& random_A_field = Field::ZoneHandle( | 1402 const Field& random_A_field = Field::ZoneHandle( |
| 1444 random_class.LookupStaticField(Symbols::_A())); | 1403 random_class.LookupStaticField(Symbols::_A())); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1466 __ lw(T3, addr_1); | 1425 __ lw(T3, addr_1); |
| 1467 __ mtlo(T3); | 1426 __ mtlo(T3); |
| 1468 __ mthi(ZR); // HI:LO <- ZR:T3 Zero extend T3 into HI. | 1427 __ mthi(ZR); // HI:LO <- ZR:T3 Zero extend T3 into HI. |
| 1469 // 64-bit multiply and accumulate into T6:T3. | 1428 // 64-bit multiply and accumulate into T6:T3. |
| 1470 __ maddu(T0, T2); // HI:LO <- HI:LO + T0 * T2. | 1429 __ maddu(T0, T2); // HI:LO <- HI:LO + T0 * T2. |
| 1471 __ mflo(T3); | 1430 __ mflo(T3); |
| 1472 __ mfhi(T6); | 1431 __ mfhi(T6); |
| 1473 __ sw(T3, addr_0); | 1432 __ sw(T3, addr_0); |
| 1474 __ sw(T6, addr_1); | 1433 __ sw(T6, addr_1); |
| 1475 __ Ret(); | 1434 __ Ret(); |
| 1476 return true; | |
| 1477 } | 1435 } |
| 1478 | 1436 |
| 1479 | 1437 |
| 1480 bool Intrinsifier::Object_equal(Assembler* assembler) { | 1438 void Intrinsifier::Object_equal(Assembler* assembler) { |
| 1481 Label is_true; | 1439 Label is_true; |
| 1482 | 1440 |
| 1483 __ lw(T0, Address(SP, 0 * kWordSize)); | 1441 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1484 __ lw(T1, Address(SP, 1 * kWordSize)); | 1442 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 1485 __ beq(T0, T1, &is_true); | 1443 __ beq(T0, T1, &is_true); |
| 1486 __ LoadObject(V0, Bool::False()); | 1444 __ LoadObject(V0, Bool::False()); |
| 1487 __ Ret(); | 1445 __ Ret(); |
| 1488 __ Bind(&is_true); | 1446 __ Bind(&is_true); |
| 1489 __ LoadObject(V0, Bool::True()); | 1447 __ LoadObject(V0, Bool::True()); |
| 1490 __ Ret(); | 1448 __ Ret(); |
| 1491 return true; | |
| 1492 } | 1449 } |
| 1493 | 1450 |
| 1494 | 1451 |
| 1495 bool Intrinsifier::String_getHashCode(Assembler* assembler) { | 1452 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1496 Label fall_through; | 1453 Label fall_through; |
| 1497 __ lw(T0, Address(SP, 0 * kWordSize)); | 1454 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1498 __ lw(V0, FieldAddress(T0, String::hash_offset())); | 1455 __ lw(V0, FieldAddress(T0, String::hash_offset())); |
| 1499 __ beq(V0, ZR, &fall_through); | 1456 __ beq(V0, ZR, &fall_through); |
| 1500 __ Ret(); | 1457 __ Ret(); |
| 1501 __ Bind(&fall_through); // Hash not yet computed. | 1458 __ Bind(&fall_through); // Hash not yet computed. |
| 1502 return false; | |
| 1503 } | 1459 } |
| 1504 | 1460 |
| 1505 | 1461 |
| 1506 bool Intrinsifier::String_getLength(Assembler* assembler) { | 1462 void Intrinsifier::String_getLength(Assembler* assembler) { |
| 1507 __ lw(T0, Address(SP, 0 * kWordSize)); | 1463 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1508 __ Ret(); | 1464 __ Ret(); |
| 1509 __ delay_slot()->lw(V0, FieldAddress(T0, String::length_offset())); | 1465 __ delay_slot()->lw(V0, FieldAddress(T0, String::length_offset())); |
| 1510 return true; | |
| 1511 } | 1466 } |
| 1512 | 1467 |
| 1513 | 1468 |
| 1514 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1469 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { |
| 1515 Label fall_through, try_two_byte_string; | 1470 Label fall_through, try_two_byte_string; |
| 1516 | 1471 |
| 1517 __ lw(T1, Address(SP, 0 * kWordSize)); // Index. | 1472 __ lw(T1, Address(SP, 0 * kWordSize)); // Index. |
| 1518 __ lw(T0, Address(SP, 1 * kWordSize)); // String. | 1473 __ lw(T0, Address(SP, 1 * kWordSize)); // String. |
| 1519 | 1474 |
| 1520 // Checks. | 1475 // Checks. |
| 1521 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | 1476 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); |
| 1522 __ bne(T1, ZR, &fall_through); // Index is not a Smi. | 1477 __ bne(T1, ZR, &fall_through); // Index is not a Smi. |
| 1523 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check. | 1478 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check. |
| 1524 // Runtime throws exception. | 1479 // Runtime throws exception. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1535 | 1490 |
| 1536 __ Bind(&try_two_byte_string); | 1491 __ Bind(&try_two_byte_string); |
| 1537 __ BranchNotEqual(CMPRES1, kTwoByteStringCid, &fall_through); | 1492 __ BranchNotEqual(CMPRES1, kTwoByteStringCid, &fall_through); |
| 1538 ASSERT(kSmiTagShift == 1); | 1493 ASSERT(kSmiTagShift == 1); |
| 1539 __ addu(T2, T0, T1); | 1494 __ addu(T2, T0, T1); |
| 1540 __ lhu(V0, FieldAddress(T2, OneByteString::data_offset())); | 1495 __ lhu(V0, FieldAddress(T2, OneByteString::data_offset())); |
| 1541 __ Ret(); | 1496 __ Ret(); |
| 1542 __ delay_slot()->SmiTag(V0); | 1497 __ delay_slot()->SmiTag(V0); |
| 1543 | 1498 |
| 1544 __ Bind(&fall_through); | 1499 __ Bind(&fall_through); |
| 1545 return false; | |
| 1546 } | 1500 } |
| 1547 | 1501 |
| 1548 | 1502 |
| 1549 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { | 1503 void Intrinsifier::String_getIsEmpty(Assembler* assembler) { |
| 1550 Label is_true; | 1504 Label is_true; |
| 1551 | 1505 |
| 1552 __ lw(T0, Address(SP, 0 * kWordSize)); | 1506 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1553 __ lw(T0, FieldAddress(T0, String::length_offset())); | 1507 __ lw(T0, FieldAddress(T0, String::length_offset())); |
| 1554 | 1508 |
| 1555 __ beq(T0, ZR, &is_true); | 1509 __ beq(T0, ZR, &is_true); |
| 1556 __ LoadObject(V0, Bool::False()); | 1510 __ LoadObject(V0, Bool::False()); |
| 1557 __ Ret(); | 1511 __ Ret(); |
| 1558 __ Bind(&is_true); | 1512 __ Bind(&is_true); |
| 1559 __ LoadObject(V0, Bool::True()); | 1513 __ LoadObject(V0, Bool::True()); |
| 1560 __ Ret(); | 1514 __ Ret(); |
| 1561 return false; | |
| 1562 } | 1515 } |
| 1563 | 1516 |
| 1564 | 1517 |
| 1565 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1518 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
| 1566 Label no_hash; | 1519 Label no_hash; |
| 1567 | 1520 |
| 1568 __ lw(T1, Address(SP, 0 * kWordSize)); | 1521 __ lw(T1, Address(SP, 0 * kWordSize)); |
| 1569 __ lw(V0, FieldAddress(T1, String::hash_offset())); | 1522 __ lw(V0, FieldAddress(T1, String::hash_offset())); |
| 1570 __ beq(V0, ZR, &no_hash); | 1523 __ beq(V0, ZR, &no_hash); |
| 1571 __ Ret(); // Return if already computed. | 1524 __ Ret(); // Return if already computed. |
| 1572 __ Bind(&no_hash); | 1525 __ Bind(&no_hash); |
| 1573 | 1526 |
| 1574 __ lw(T2, FieldAddress(T1, String::length_offset())); | 1527 __ lw(T2, FieldAddress(T1, String::length_offset())); |
| 1575 | 1528 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1618 __ LoadImmediate(T6, (static_cast<intptr_t>(1) << String::kHashBits) - 1); | 1571 __ LoadImmediate(T6, (static_cast<intptr_t>(1) << String::kHashBits) - 1); |
| 1619 __ and_(V0, V0, T6); | 1572 __ and_(V0, V0, T6); |
| 1620 __ Bind(&done); | 1573 __ Bind(&done); |
| 1621 | 1574 |
| 1622 __ LoadImmediate(T2, 1); | 1575 __ LoadImmediate(T2, 1); |
| 1623 __ movz(V0, T2, V0); // If V0 is 0, set to 1. | 1576 __ movz(V0, T2, V0); // If V0 is 0, set to 1. |
| 1624 __ SmiTag(V0); | 1577 __ SmiTag(V0); |
| 1625 | 1578 |
| 1626 __ Ret(); | 1579 __ Ret(); |
| 1627 __ delay_slot()->sw(V0, FieldAddress(T1, String::hash_offset())); | 1580 __ delay_slot()->sw(V0, FieldAddress(T1, String::hash_offset())); |
| 1628 return true; | |
| 1629 } | 1581 } |
| 1630 | 1582 |
| 1631 | 1583 |
| 1632 // Allocates one-byte string of length 'end - start'. The content is not | 1584 // Allocates one-byte string of length 'end - start'. The content is not |
| 1633 // initialized. | 1585 // initialized. |
| 1634 // 'length-reg' (T2) contains tagged length. | 1586 // 'length-reg' (T2) contains tagged length. |
| 1635 // Returns new string as tagged pointer in V0. | 1587 // Returns new string as tagged pointer in V0. |
| 1636 static void TryAllocateOnebyteString(Assembler* assembler, | 1588 static void TryAllocateOnebyteString(Assembler* assembler, |
| 1637 Label* ok, | 1589 Label* ok, |
| 1638 Label* failure) { | 1590 Label* failure) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1700 // Clear hash. | 1652 // Clear hash. |
| 1701 __ b(ok); | 1653 __ b(ok); |
| 1702 __ delay_slot()->sw(ZR, FieldAddress(V0, String::hash_offset())); | 1654 __ delay_slot()->sw(ZR, FieldAddress(V0, String::hash_offset())); |
| 1703 } | 1655 } |
| 1704 | 1656 |
| 1705 | 1657 |
| 1706 // Arg0: Onebyte String | 1658 // Arg0: Onebyte String |
| 1707 // Arg1: Start index as Smi. | 1659 // Arg1: Start index as Smi. |
| 1708 // Arg2: End index as Smi. | 1660 // Arg2: End index as Smi. |
| 1709 // The indexes must be valid. | 1661 // The indexes must be valid. |
| 1710 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 1662 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
| 1711 const intptr_t kStringOffset = 2 * kWordSize; | 1663 const intptr_t kStringOffset = 2 * kWordSize; |
| 1712 const intptr_t kStartIndexOffset = 1 * kWordSize; | 1664 const intptr_t kStartIndexOffset = 1 * kWordSize; |
| 1713 const intptr_t kEndIndexOffset = 0 * kWordSize; | 1665 const intptr_t kEndIndexOffset = 0 * kWordSize; |
| 1714 Label fall_through, ok; | 1666 Label fall_through, ok; |
| 1715 | 1667 |
| 1716 __ lw(T2, Address(SP, kEndIndexOffset)); | 1668 __ lw(T2, Address(SP, kEndIndexOffset)); |
| 1717 __ lw(TMP, Address(SP, kStartIndexOffset)); | 1669 __ lw(TMP, Address(SP, kStartIndexOffset)); |
| 1718 __ subu(T2, T2, TMP); | 1670 __ subu(T2, T2, TMP); |
| 1719 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 1671 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 1720 __ Bind(&ok); | 1672 __ Bind(&ok); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1747 __ lbu(T1, Address(T6, 0)); | 1699 __ lbu(T1, Address(T6, 0)); |
| 1748 __ AddImmediate(T6, 1); | 1700 __ AddImmediate(T6, 1); |
| 1749 __ addiu(T2, T2, Immediate(-1)); | 1701 __ addiu(T2, T2, Immediate(-1)); |
| 1750 __ sb(T1, FieldAddress(T7, OneByteString::data_offset())); | 1702 __ sb(T1, FieldAddress(T7, OneByteString::data_offset())); |
| 1751 __ bgtz(T2, &loop); | 1703 __ bgtz(T2, &loop); |
| 1752 __ delay_slot()->addiu(T7, T7, Immediate(1)); | 1704 __ delay_slot()->addiu(T7, T7, Immediate(1)); |
| 1753 | 1705 |
| 1754 __ Bind(&done); | 1706 __ Bind(&done); |
| 1755 __ Ret(); | 1707 __ Ret(); |
| 1756 __ Bind(&fall_through); | 1708 __ Bind(&fall_through); |
| 1757 return false; | |
| 1758 } | 1709 } |
| 1759 | 1710 |
| 1760 | 1711 |
| 1761 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { | 1712 void Intrinsifier::OneByteString_setAt(Assembler* assembler) { |
| 1762 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 1713 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 1763 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. | 1714 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. |
| 1764 __ lw(T0, Address(SP, 2 * kWordSize)); // OneByteString. | 1715 __ lw(T0, Address(SP, 2 * kWordSize)); // OneByteString. |
| 1765 __ SmiUntag(T1); | 1716 __ SmiUntag(T1); |
| 1766 __ SmiUntag(T2); | 1717 __ SmiUntag(T2); |
| 1767 __ addu(T3, T0, T1); | 1718 __ addu(T3, T0, T1); |
| 1768 __ Ret(); | 1719 __ Ret(); |
| 1769 __ delay_slot()->sb(T2, FieldAddress(T3, OneByteString::data_offset())); | 1720 __ delay_slot()->sb(T2, FieldAddress(T3, OneByteString::data_offset())); |
| 1770 return true; | |
| 1771 } | 1721 } |
| 1772 | 1722 |
| 1773 | 1723 |
| 1774 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { | 1724 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { |
| 1775 Label fall_through, ok; | 1725 Label fall_through, ok; |
| 1776 | 1726 |
| 1777 __ lw(T2, Address(SP, 0 * kWordSize)); // Length. | 1727 __ lw(T2, Address(SP, 0 * kWordSize)); // Length. |
| 1778 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 1728 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 1779 | 1729 |
| 1780 __ Bind(&ok); | 1730 __ Bind(&ok); |
| 1781 __ Ret(); | 1731 __ Ret(); |
| 1782 | 1732 |
| 1783 __ Bind(&fall_through); | 1733 __ Bind(&fall_through); |
| 1784 return false; | |
| 1785 } | 1734 } |
| 1786 | 1735 |
| 1787 } // namespace dart | 1736 } // namespace dart |
| 1788 | 1737 |
| 1789 #endif // defined TARGET_ARCH_MIPS | 1738 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |