| 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 | 23 |
| 24 void Intrinsifier::Array_getLength(Assembler* assembler) { | 24 void Intrinsifier::ObjectArrayLength(Assembler* assembler) { |
| 25 __ lw(V0, Address(SP, 0 * kWordSize)); | 25 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 26 __ Ret(); | 26 __ Ret(); |
| 27 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); | 27 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); |
| 28 } | 28 } |
| 29 | 29 |
| 30 | 30 |
| 31 void Intrinsifier::ImmutableList_getLength(Assembler* assembler) { | 31 void Intrinsifier::ImmutableArrayLength(Assembler* assembler) { |
| 32 Array_getLength(assembler); | 32 ObjectArrayLength(assembler); |
| 33 } | 33 } |
| 34 | 34 |
| 35 | 35 |
| 36 void Intrinsifier::Array_getIndexed(Assembler* assembler) { | 36 void Intrinsifier::ObjectArrayGetIndexed(Assembler* assembler) { |
| 37 Label fall_through; | 37 Label fall_through; |
| 38 | 38 |
| 39 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index | 39 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index |
| 40 | 40 |
| 41 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 41 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 42 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through | 42 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through |
| 43 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array | 43 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array |
| 44 | 44 |
| 45 // Range check. | 45 // Range check. |
| 46 __ lw(T2, FieldAddress(T1, Array::length_offset())); | 46 __ lw(T2, FieldAddress(T1, Array::length_offset())); |
| 47 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 47 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 48 | 48 |
| 49 ASSERT(kSmiTagShift == 1); | 49 ASSERT(kSmiTagShift == 1); |
| 50 // array element at T1 + T0*2 + Array::data_offset - 1 | 50 // array element at T1 + T0*2 + Array::data_offset - 1 |
| 51 __ sll(T2, T0, 1); | 51 __ sll(T2, T0, 1); |
| 52 __ addu(T2, T1, T2); | 52 __ addu(T2, T1, T2); |
| 53 __ Ret(); | 53 __ Ret(); |
| 54 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); | 54 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); |
| 55 __ Bind(&fall_through); | 55 __ Bind(&fall_through); |
| 56 } | 56 } |
| 57 | 57 |
| 58 | 58 |
| 59 void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) { | 59 void Intrinsifier::ImmutableArrayGetIndexed(Assembler* assembler) { |
| 60 Array_getIndexed(assembler); | 60 ObjectArrayGetIndexed(assembler); |
| 61 } | 61 } |
| 62 | 62 |
| 63 | 63 |
| 64 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 64 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 65 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 65 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 66 const Class& cls = Class::Handle( | 66 const Class& cls = Class::Handle( |
| 67 core_lib.LookupClassAllowPrivate(Symbols::_List())); | 67 core_lib.LookupClassAllowPrivate(Symbols::_List())); |
| 68 ASSERT(!cls.IsNull()); | 68 ASSERT(!cls.IsNull()); |
| 69 ASSERT(cls.NumTypeArguments() == 1); | 69 ASSERT(cls.NumTypeArguments() == 1); |
| 70 const intptr_t field_offset = cls.type_arguments_field_offset(); | 70 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 71 ASSERT(field_offset != Class::kNoTypeArguments); | 71 ASSERT(field_offset != Class::kNoTypeArguments); |
| 72 return field_offset; | 72 return field_offset; |
| 73 } | 73 } |
| 74 | 74 |
| 75 | 75 |
| 76 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 76 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
| 77 // update. Array length is always a Smi. | 77 // update. Array length is always a Smi. |
| 78 void Intrinsifier::Array_setIndexed(Assembler* assembler) { | 78 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) { |
| 79 Label fall_through; | 79 Label fall_through; |
| 80 | 80 |
| 81 if (FLAG_enable_type_checks) { | 81 if (FLAG_enable_type_checks) { |
| 82 const intptr_t type_args_field_offset = | 82 const intptr_t type_args_field_offset = |
| 83 ComputeObjectArrayTypeArgumentsOffset(); | 83 ComputeObjectArrayTypeArgumentsOffset(); |
| 84 // Inline simple tests (Smi, null), fallthrough if not positive. | 84 // Inline simple tests (Smi, null), fallthrough if not positive. |
| 85 Label checked_ok; | 85 Label checked_ok; |
| 86 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 86 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 87 | 87 |
| 88 // Null value is valid for any type. | 88 // Null value is valid for any type. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 FieldAddress(T1, Array::data_offset()), | 128 FieldAddress(T1, Array::data_offset()), |
| 129 T2); | 129 T2); |
| 130 // Caller is responsible for preserving the value if necessary. | 130 // Caller is responsible for preserving the value if necessary. |
| 131 __ Ret(); | 131 __ Ret(); |
| 132 __ Bind(&fall_through); | 132 __ Bind(&fall_through); |
| 133 } | 133 } |
| 134 | 134 |
| 135 | 135 |
| 136 // Allocate a GrowableObjectArray using the backing array specified. | 136 // Allocate a GrowableObjectArray using the backing array specified. |
| 137 // On stack: type argument (+1), data (+0). | 137 // On stack: type argument (+1), data (+0). |
| 138 void Intrinsifier::GrowableList_Allocate(Assembler* assembler) { | 138 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 139 // The newly allocated object is returned in V0. | 139 // The newly allocated object is returned in V0. |
| 140 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 140 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 141 const intptr_t kArrayOffset = 0 * kWordSize; | 141 const intptr_t kArrayOffset = 0 * kWordSize; |
| 142 Label fall_through; | 142 Label fall_through; |
| 143 | 143 |
| 144 // Try allocating in new space. | 144 // Try allocating in new space. |
| 145 const Class& cls = Class::Handle( | 145 const Class& cls = Class::Handle( |
| 146 Isolate::Current()->object_store()->growable_object_array_class()); | 146 Isolate::Current()->object_store()->growable_object_array_class()); |
| 147 __ TryAllocate(cls, &fall_through, V0, T1); | 147 __ TryAllocate(cls, &fall_through, V0, T1); |
| 148 | 148 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 163 T1); | 163 T1); |
| 164 // Set the length field in the growable array object to 0. | 164 // Set the length field in the growable array object to 0. |
| 165 __ Ret(); // Returns the newly allocated object in V0. | 165 __ Ret(); // Returns the newly allocated object in V0. |
| 166 __ delay_slot()->sw(ZR, | 166 __ delay_slot()->sw(ZR, |
| 167 FieldAddress(V0, GrowableObjectArray::length_offset())); | 167 FieldAddress(V0, GrowableObjectArray::length_offset())); |
| 168 | 168 |
| 169 __ Bind(&fall_through); | 169 __ Bind(&fall_through); |
| 170 } | 170 } |
| 171 | 171 |
| 172 | 172 |
| 173 void Intrinsifier::GrowableList_getLength(Assembler* assembler) { | 173 void Intrinsifier::GrowableArrayLength(Assembler* assembler) { |
| 174 __ lw(V0, Address(SP, 0 * kWordSize)); | 174 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 175 __ Ret(); | 175 __ Ret(); |
| 176 __ delay_slot()->lw(V0, | 176 __ delay_slot()->lw(V0, |
| 177 FieldAddress(V0, GrowableObjectArray::length_offset())); | 177 FieldAddress(V0, GrowableObjectArray::length_offset())); |
| 178 } | 178 } |
| 179 | 179 |
| 180 | 180 |
| 181 void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) { | 181 void Intrinsifier::GrowableArrayCapacity(Assembler* assembler) { |
| 182 __ lw(V0, Address(SP, 0 * kWordSize)); | 182 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 183 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset())); | 183 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset())); |
| 184 __ Ret(); | 184 __ Ret(); |
| 185 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); | 185 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); |
| 186 } | 186 } |
| 187 | 187 |
| 188 | 188 |
| 189 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { | 189 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { |
| 190 Label fall_through; | 190 Label fall_through; |
| 191 | 191 |
| 192 __ lw(T0, Address(SP, 0 * kWordSize)); // Index | 192 __ lw(T0, Address(SP, 0 * kWordSize)); // Index |
| 193 | 193 |
| 194 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 194 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 195 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through | 195 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through |
| 196 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array | 196 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array |
| 197 | 197 |
| 198 // Range check. | 198 // Range check. |
| 199 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); | 199 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); |
| 200 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 200 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 201 | 201 |
| 202 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data | 202 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data |
| 203 | 203 |
| 204 ASSERT(kSmiTagShift == 1); | 204 ASSERT(kSmiTagShift == 1); |
| 205 // array element at T2 + T0 * 2 + Array::data_offset - 1 | 205 // array element at T2 + T0 * 2 + Array::data_offset - 1 |
| 206 __ sll(T3, T0, 1); | 206 __ sll(T3, T0, 1); |
| 207 __ addu(T2, T2, T3); | 207 __ addu(T2, T2, T3); |
| 208 __ Ret(); | 208 __ Ret(); |
| 209 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); | 209 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); |
| 210 __ Bind(&fall_through); | 210 __ Bind(&fall_through); |
| 211 } | 211 } |
| 212 | 212 |
| 213 | 213 |
| 214 // Set value into growable object array at specified index. | 214 // Set value into growable object array at specified index. |
| 215 // On stack: growable array (+2), index (+1), value (+0). | 215 // On stack: growable array (+2), index (+1), value (+0). |
| 216 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { | 216 void Intrinsifier::GrowableArraySetIndexed(Assembler* assembler) { |
| 217 if (FLAG_enable_type_checks) { | 217 if (FLAG_enable_type_checks) { |
| 218 return; | 218 return; |
| 219 } | 219 } |
| 220 Label fall_through; | 220 Label fall_through; |
| 221 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. | 221 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. |
| 222 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); | 222 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 223 __ bne(CMPRES1, ZR, &fall_through); // Non-smi index. | 223 __ bne(CMPRES1, ZR, &fall_through); // Non-smi index. |
| 224 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. | 224 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 225 // Range check using _length field. | 225 // Range check using _length field. |
| 226 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); | 226 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 227 // Runtime throws exception. | 227 // Runtime throws exception. |
| 228 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); | 228 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); |
| 229 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. | 229 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. |
| 230 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 230 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 231 // Note that T1 is Smi, i.e, times 2. | 231 // Note that T1 is Smi, i.e, times 2. |
| 232 ASSERT(kSmiTagShift == 1); | 232 ASSERT(kSmiTagShift == 1); |
| 233 __ sll(T1, T1, 1); | 233 __ sll(T1, T1, 1); |
| 234 __ addu(T1, T0, T1); | 234 __ addu(T1, T0, T1); |
| 235 __ StoreIntoObject(T0, | 235 __ StoreIntoObject(T0, |
| 236 FieldAddress(T1, Array::data_offset()), | 236 FieldAddress(T1, Array::data_offset()), |
| 237 T2); | 237 T2); |
| 238 __ Ret(); | 238 __ Ret(); |
| 239 __ Bind(&fall_through); | 239 __ Bind(&fall_through); |
| 240 } | 240 } |
| 241 | 241 |
| 242 | 242 |
| 243 // Set length of growable object array. The length cannot | 243 // Set length of growable object array. The length cannot |
| 244 // be greater than the length of the data container. | 244 // be greater than the length of the data container. |
| 245 // On stack: growable array (+1), length (+0). | 245 // On stack: growable array (+1), length (+0). |
| 246 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { | 246 void Intrinsifier::GrowableArraySetLength(Assembler* assembler) { |
| 247 Label fall_through; | 247 Label fall_through; |
| 248 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. | 248 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. |
| 249 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); | 249 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 250 __ bne(CMPRES1, ZR, &fall_through); // Non-smi length. | 250 __ bne(CMPRES1, ZR, &fall_through); // Non-smi length. |
| 251 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 251 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 252 __ Ret(); | 252 __ Ret(); |
| 253 __ delay_slot()->sw(T1, | 253 __ delay_slot()->sw(T1, |
| 254 FieldAddress(T0, GrowableObjectArray::length_offset())); | 254 FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 255 __ Bind(&fall_through); | 255 __ Bind(&fall_through); |
| 256 } | 256 } |
| 257 | 257 |
| 258 | 258 |
| 259 // Set data of growable object array. | 259 // Set data of growable object array. |
| 260 // On stack: growable array (+1), data (+0). | 260 // On stack: growable array (+1), data (+0). |
| 261 void Intrinsifier::GrowableList_setData(Assembler* assembler) { | 261 void Intrinsifier::GrowableArraySetData(Assembler* assembler) { |
| 262 if (FLAG_enable_type_checks) { | 262 if (FLAG_enable_type_checks) { |
| 263 return; | 263 return; |
| 264 } | 264 } |
| 265 Label fall_through; | 265 Label fall_through; |
| 266 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. | 266 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. |
| 267 // Check that data is an ObjectArray. | 267 // Check that data is an ObjectArray. |
| 268 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); | 268 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 269 __ beq(CMPRES1, ZR, &fall_through); // Data is Smi. | 269 __ beq(CMPRES1, ZR, &fall_through); // Data is Smi. |
| 270 __ LoadClassId(CMPRES1, T1); | 270 __ LoadClassId(CMPRES1, T1); |
| 271 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); | 271 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); |
| 272 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. | 272 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. |
| 273 __ StoreIntoObject(T0, | 273 __ StoreIntoObject(T0, |
| 274 FieldAddress(T0, GrowableObjectArray::data_offset()), | 274 FieldAddress(T0, GrowableObjectArray::data_offset()), |
| 275 T1); | 275 T1); |
| 276 __ Ret(); | 276 __ Ret(); |
| 277 __ Bind(&fall_through); | 277 __ Bind(&fall_through); |
| 278 } | 278 } |
| 279 | 279 |
| 280 | 280 |
| 281 // Add an element to growable array if it doesn't need to grow, otherwise | 281 // Add an element to growable array if it doesn't need to grow, otherwise |
| 282 // call into regular code. | 282 // call into regular code. |
| 283 // On stack: growable array (+1), value (+0). | 283 // On stack: growable array (+1), value (+0). |
| 284 void Intrinsifier::GrowableList_add(Assembler* assembler) { | 284 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
| 285 // In checked mode we need to type-check the incoming argument. | 285 // In checked mode we need to type-check the incoming argument. |
| 286 if (FLAG_enable_type_checks) return; | 286 if (FLAG_enable_type_checks) return; |
| 287 Label fall_through; | 287 Label fall_through; |
| 288 __ lw(T0, Address(SP, 1 * kWordSize)); // Array. | 288 __ lw(T0, Address(SP, 1 * kWordSize)); // Array. |
| 289 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset())); | 289 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset())); |
| 290 // T1: length. | 290 // T1: length. |
| 291 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset())); | 291 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset())); |
| 292 // T2: data. | 292 // T2: data. |
| 293 __ lw(T3, FieldAddress(T2, Array::length_offset())); | 293 __ lw(T3, FieldAddress(T2, Array::length_offset())); |
| 294 // Compare length with capacity. | 294 // Compare length with capacity. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 __ sw(ZR, Address(T2, 0)); \ | 393 __ sw(ZR, Address(T2, 0)); \ |
| 394 __ b(&init_loop); \ | 394 __ b(&init_loop); \ |
| 395 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); \ | 395 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); \ |
| 396 __ Bind(&done); \ | 396 __ Bind(&done); \ |
| 397 \ | 397 \ |
| 398 __ Ret(); \ | 398 __ Ret(); \ |
| 399 __ Bind(&fall_through); \ | 399 __ Bind(&fall_through); \ |
| 400 | 400 |
| 401 | 401 |
| 402 // Gets the length of a TypedData. | 402 // Gets the length of a TypedData. |
| 403 void Intrinsifier::TypedData_getLength(Assembler* assembler) { | 403 void Intrinsifier::TypedDataLength(Assembler* assembler) { |
| 404 __ lw(T0, Address(SP, 0 * kWordSize)); | 404 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 405 __ Ret(); | 405 __ Ret(); |
| 406 __ delay_slot()->lw(V0, FieldAddress(T0, TypedData::length_offset())); | 406 __ delay_slot()->lw(V0, FieldAddress(T0, TypedData::length_offset())); |
| 407 } | 407 } |
| 408 | 408 |
| 409 | 409 |
| 410 void Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) { | 410 void Intrinsifier::Uint8ArrayGetIndexed(Assembler* assembler) { |
| 411 Label fall_through; | 411 Label fall_through; |
| 412 | 412 |
| 413 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index. | 413 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index. |
| 414 | 414 |
| 415 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 415 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 416 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. | 416 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. |
| 417 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array. | 417 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array. |
| 418 | 418 |
| 419 // Range check. | 419 // Range check. |
| 420 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); | 420 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); |
| 421 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 421 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 422 | 422 |
| 423 __ SmiUntag(T0); | 423 __ SmiUntag(T0); |
| 424 __ addu(T1, T1, T0); | 424 __ addu(T1, T1, T0); |
| 425 __ lbu(V0, FieldAddress(T1, TypedData::data_offset())); | 425 __ lbu(V0, FieldAddress(T1, TypedData::data_offset())); |
| 426 __ Ret(); | 426 __ Ret(); |
| 427 __ delay_slot()->SmiTag(V0); | 427 __ delay_slot()->SmiTag(V0); |
| 428 | 428 |
| 429 __ Bind(&fall_through); | 429 __ Bind(&fall_through); |
| 430 } | 430 } |
| 431 | 431 |
| 432 | 432 |
| 433 void Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) { | 433 void Intrinsifier::ExternalUint8ArrayGetIndexed(Assembler* assembler) { |
| 434 Label fall_through; | 434 Label fall_through; |
| 435 | 435 |
| 436 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index. | 436 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index. |
| 437 | 437 |
| 438 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 438 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 439 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. | 439 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. |
| 440 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array. | 440 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array. |
| 441 | 441 |
| 442 // Range check. | 442 // Range check. |
| 443 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); | 443 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); |
| 444 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); | 444 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); |
| 445 | 445 |
| 446 __ lw(T1, FieldAddress(T1, ExternalTypedData::data_offset())); | 446 __ lw(T1, FieldAddress(T1, ExternalTypedData::data_offset())); |
| 447 __ SmiUntag(T0); | 447 __ SmiUntag(T0); |
| 448 __ addu(T1, T1, T0); | 448 __ addu(T1, T1, T0); |
| 449 __ lbu(V0, Address(T1, 0)); | 449 __ lbu(V0, Address(T1, 0)); |
| 450 __ Ret(); | 450 __ Ret(); |
| 451 __ delay_slot()->SmiTag(V0); | 451 __ delay_slot()->SmiTag(V0); |
| 452 | 452 |
| 453 __ Bind(&fall_through); | 453 __ Bind(&fall_through); |
| 454 } | 454 } |
| 455 | 455 |
| 456 | 456 |
| 457 void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) { | 457 void Intrinsifier::Float64ArrayGetIndexed(Assembler* assembler) { |
| 458 Label fall_through; | 458 Label fall_through; |
| 459 | 459 |
| 460 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index. | 460 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index. |
| 461 | 461 |
| 462 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 462 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 463 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. | 463 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. |
| 464 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array. | 464 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array. |
| 465 | 465 |
| 466 // Range check. | 466 // Range check. |
| 467 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); | 467 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 482 __ TryAllocate(double_class, | 482 __ TryAllocate(double_class, |
| 483 &fall_through, | 483 &fall_through, |
| 484 V0, // Result register. | 484 V0, // Result register. |
| 485 T1); | 485 T1); |
| 486 __ StoreDToOffset(D0, V0, Double::value_offset() - kHeapObjectTag); | 486 __ StoreDToOffset(D0, V0, Double::value_offset() - kHeapObjectTag); |
| 487 __ Ret(); | 487 __ Ret(); |
| 488 __ Bind(&fall_through); | 488 __ Bind(&fall_through); |
| 489 } | 489 } |
| 490 | 490 |
| 491 | 491 |
| 492 void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) { | 492 void Intrinsifier::Float64ArraySetIndexed(Assembler* assembler) { |
| 493 Label fall_through; | 493 Label fall_through; |
| 494 | 494 |
| 495 __ lw(T0, Address(SP, + 1 * kWordSize)); // Index. | 495 __ lw(T0, Address(SP, + 1 * kWordSize)); // Index. |
| 496 | 496 |
| 497 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 497 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 498 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. | 498 __ bne(CMPRES1, ZR, &fall_through); // Index is not an smi, fall through. |
| 499 __ delay_slot()->lw(T1, Address(SP, + 2 * kWordSize)); // Array. | 499 __ delay_slot()->lw(T1, Address(SP, + 2 * kWordSize)); // Array. |
| 500 | 500 |
| 501 // Range check. | 501 // Range check. |
| 502 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); | 502 __ lw(T2, FieldAddress(T1, TypedData::length_offset())); |
| (...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1286 __ Bind(&is_zero); | 1286 __ Bind(&is_zero); |
| 1287 // Check for negative zero by looking at the sign bit. | 1287 // Check for negative zero by looking at the sign bit. |
| 1288 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0. | 1288 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0. |
| 1289 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0. | 1289 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0. |
| 1290 __ andi(CMPRES1, T0, Immediate(1)); // Check if the bit is set. | 1290 __ andi(CMPRES1, T0, Immediate(1)); // Check if the bit is set. |
| 1291 __ bne(T0, ZR, &is_true); // Sign bit set. True. | 1291 __ bne(T0, ZR, &is_true); // Sign bit set. True. |
| 1292 __ b(&is_false); | 1292 __ b(&is_false); |
| 1293 } | 1293 } |
| 1294 | 1294 |
| 1295 | 1295 |
| 1296 void Intrinsifier::Double_toInt(Assembler* assembler) { | 1296 void Intrinsifier::DoubleToInteger(Assembler* assembler) { |
| 1297 __ lw(T0, Address(SP, 0 * kWordSize)); | 1297 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1298 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); | 1298 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); |
| 1299 | 1299 |
| 1300 __ cvtwd(F2, D0); | 1300 __ cvtwd(F2, D0); |
| 1301 __ mfc1(V0, F2); | 1301 __ mfc1(V0, F2); |
| 1302 | 1302 |
| 1303 // Overflow is signaled with minint. | 1303 // Overflow is signaled with minint. |
| 1304 Label fall_through; | 1304 Label fall_through; |
| 1305 // Check for overflow and that it fits into Smi. | 1305 // Check for overflow and that it fits into Smi. |
| 1306 __ LoadImmediate(TMP, 0xC0000000); | 1306 __ LoadImmediate(TMP, 0xC0000000); |
| 1307 __ subu(CMPRES1, V0, TMP); | 1307 __ subu(CMPRES1, V0, TMP); |
| 1308 __ bltz(CMPRES1, &fall_through); | 1308 __ bltz(CMPRES1, &fall_through); |
| 1309 __ Ret(); | 1309 __ Ret(); |
| 1310 __ delay_slot()->SmiTag(V0); | 1310 __ delay_slot()->SmiTag(V0); |
| 1311 __ Bind(&fall_through); | 1311 __ Bind(&fall_through); |
| 1312 } | 1312 } |
| 1313 | 1313 |
| 1314 | 1314 |
| 1315 void Intrinsifier::Math_sqrt(Assembler* assembler) { | 1315 void Intrinsifier::MathSqrt(Assembler* assembler) { |
| 1316 Label fall_through, is_smi, double_op; | 1316 Label fall_through, is_smi, double_op; |
| 1317 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1317 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1318 // Argument is double and is in T0. | 1318 // Argument is double and is in T0. |
| 1319 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); | 1319 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); |
| 1320 __ Bind(&double_op); | 1320 __ Bind(&double_op); |
| 1321 __ sqrtd(D0, D1); | 1321 __ sqrtd(D0, D1); |
| 1322 const Class& double_class = Class::Handle( | 1322 const Class& double_class = Class::Handle( |
| 1323 Isolate::Current()->object_store()->double_class()); | 1323 Isolate::Current()->object_store()->double_class()); |
| 1324 __ TryAllocate(double_class, &fall_through, V0, T1); // Result register. | 1324 __ TryAllocate(double_class, &fall_through, V0, T1); // Result register. |
| 1325 __ swc1(F0, FieldAddress(V0, Double::value_offset())); | 1325 __ swc1(F0, FieldAddress(V0, Double::value_offset())); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1375 // 64-bit multiply and accumulate into T6:T3. | 1375 // 64-bit multiply and accumulate into T6:T3. |
| 1376 __ maddu(T0, T2); // HI:LO <- HI:LO + T0 * T2. | 1376 __ maddu(T0, T2); // HI:LO <- HI:LO + T0 * T2. |
| 1377 __ mflo(T3); | 1377 __ mflo(T3); |
| 1378 __ mfhi(T6); | 1378 __ mfhi(T6); |
| 1379 __ sw(T3, addr_0); | 1379 __ sw(T3, addr_0); |
| 1380 __ sw(T6, addr_1); | 1380 __ sw(T6, addr_1); |
| 1381 __ Ret(); | 1381 __ Ret(); |
| 1382 } | 1382 } |
| 1383 | 1383 |
| 1384 | 1384 |
| 1385 void Intrinsifier::Object_equal(Assembler* assembler) { | 1385 void Intrinsifier::ObjectEquals(Assembler* assembler) { |
| 1386 Label is_true; | 1386 Label is_true; |
| 1387 | 1387 |
| 1388 __ lw(T0, Address(SP, 0 * kWordSize)); | 1388 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1389 __ lw(T1, Address(SP, 1 * kWordSize)); | 1389 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 1390 __ beq(T0, T1, &is_true); | 1390 __ beq(T0, T1, &is_true); |
| 1391 __ LoadObject(V0, Bool::False()); | 1391 __ LoadObject(V0, Bool::False()); |
| 1392 __ Ret(); | 1392 __ Ret(); |
| 1393 __ Bind(&is_true); | 1393 __ Bind(&is_true); |
| 1394 __ LoadObject(V0, Bool::True()); | 1394 __ LoadObject(V0, Bool::True()); |
| 1395 __ Ret(); | 1395 __ Ret(); |
| 1396 } | 1396 } |
| 1397 | 1397 |
| 1398 | 1398 |
| 1399 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1399 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1400 Label fall_through; | 1400 Label fall_through; |
| 1401 __ lw(T0, Address(SP, 0 * kWordSize)); | 1401 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1402 __ lw(V0, FieldAddress(T0, String::hash_offset())); | 1402 __ lw(V0, FieldAddress(T0, String::hash_offset())); |
| 1403 __ beq(V0, ZR, &fall_through); | 1403 __ beq(V0, ZR, &fall_through); |
| 1404 __ Ret(); | 1404 __ Ret(); |
| 1405 __ Bind(&fall_through); // Hash not yet computed. | 1405 __ Bind(&fall_through); // Hash not yet computed. |
| 1406 } | 1406 } |
| 1407 | 1407 |
| 1408 | 1408 |
| 1409 void Intrinsifier::String_getLength(Assembler* assembler) { | 1409 void Intrinsifier::StringBaseLength(Assembler* assembler) { |
| 1410 __ lw(T0, Address(SP, 0 * kWordSize)); | 1410 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1411 __ Ret(); | 1411 __ Ret(); |
| 1412 __ delay_slot()->lw(V0, FieldAddress(T0, String::length_offset())); | 1412 __ delay_slot()->lw(V0, FieldAddress(T0, String::length_offset())); |
| 1413 } | 1413 } |
| 1414 | 1414 |
| 1415 | 1415 |
| 1416 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1416 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { |
| 1417 Label fall_through, try_two_byte_string; | 1417 Label fall_through, try_two_byte_string; |
| 1418 | 1418 |
| 1419 __ lw(T1, Address(SP, 0 * kWordSize)); // Index. | 1419 __ lw(T1, Address(SP, 0 * kWordSize)); // Index. |
| 1420 __ lw(T0, Address(SP, 1 * kWordSize)); // String. | 1420 __ lw(T0, Address(SP, 1 * kWordSize)); // String. |
| 1421 | 1421 |
| 1422 // Checks. | 1422 // Checks. |
| 1423 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); | 1423 __ andi(CMPRES1, T1, Immediate(kSmiTagMask)); |
| 1424 __ bne(T1, ZR, &fall_through); // Index is not a Smi. | 1424 __ bne(T1, ZR, &fall_through); // Index is not a Smi. |
| 1425 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check. | 1425 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check. |
| 1426 // Runtime throws exception. | 1426 // Runtime throws exception. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1440 ASSERT(kSmiTagShift == 1); | 1440 ASSERT(kSmiTagShift == 1); |
| 1441 __ addu(T2, T0, T1); | 1441 __ addu(T2, T0, T1); |
| 1442 __ lhu(V0, FieldAddress(T2, OneByteString::data_offset())); | 1442 __ lhu(V0, FieldAddress(T2, OneByteString::data_offset())); |
| 1443 __ Ret(); | 1443 __ Ret(); |
| 1444 __ delay_slot()->SmiTag(V0); | 1444 __ delay_slot()->SmiTag(V0); |
| 1445 | 1445 |
| 1446 __ Bind(&fall_through); | 1446 __ Bind(&fall_through); |
| 1447 } | 1447 } |
| 1448 | 1448 |
| 1449 | 1449 |
| 1450 void Intrinsifier::String_getIsEmpty(Assembler* assembler) { | 1450 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
| 1451 Label is_true; | 1451 Label is_true; |
| 1452 | 1452 |
| 1453 __ lw(T0, Address(SP, 0 * kWordSize)); | 1453 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1454 __ lw(T0, FieldAddress(T0, String::length_offset())); | 1454 __ lw(T0, FieldAddress(T0, String::length_offset())); |
| 1455 | 1455 |
| 1456 __ beq(T0, ZR, &is_true); | 1456 __ beq(T0, ZR, &is_true); |
| 1457 __ LoadObject(V0, Bool::False()); | 1457 __ LoadObject(V0, Bool::False()); |
| 1458 __ Ret(); | 1458 __ Ret(); |
| 1459 __ Bind(&is_true); | 1459 __ Bind(&is_true); |
| 1460 __ LoadObject(V0, Bool::True()); | 1460 __ LoadObject(V0, Bool::True()); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1655 __ sb(T1, FieldAddress(T7, OneByteString::data_offset())); | 1655 __ sb(T1, FieldAddress(T7, OneByteString::data_offset())); |
| 1656 __ bgtz(T2, &loop); | 1656 __ bgtz(T2, &loop); |
| 1657 __ delay_slot()->addiu(T7, T7, Immediate(1)); | 1657 __ delay_slot()->addiu(T7, T7, Immediate(1)); |
| 1658 | 1658 |
| 1659 __ Bind(&done); | 1659 __ Bind(&done); |
| 1660 __ Ret(); | 1660 __ Ret(); |
| 1661 __ Bind(&fall_through); | 1661 __ Bind(&fall_through); |
| 1662 } | 1662 } |
| 1663 | 1663 |
| 1664 | 1664 |
| 1665 void Intrinsifier::OneByteString_setAt(Assembler* assembler) { | 1665 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { |
| 1666 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. | 1666 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. |
| 1667 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. | 1667 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. |
| 1668 __ lw(T0, Address(SP, 2 * kWordSize)); // OneByteString. | 1668 __ lw(T0, Address(SP, 2 * kWordSize)); // OneByteString. |
| 1669 __ SmiUntag(T1); | 1669 __ SmiUntag(T1); |
| 1670 __ SmiUntag(T2); | 1670 __ SmiUntag(T2); |
| 1671 __ addu(T3, T0, T1); | 1671 __ addu(T3, T0, T1); |
| 1672 __ Ret(); | 1672 __ Ret(); |
| 1673 __ delay_slot()->sb(T2, FieldAddress(T3, OneByteString::data_offset())); | 1673 __ delay_slot()->sb(T2, FieldAddress(T3, OneByteString::data_offset())); |
| 1674 } | 1674 } |
| 1675 | 1675 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1786 Isolate* isolate = Isolate::Current(); | 1786 Isolate* isolate = Isolate::Current(); |
| 1787 __ LoadImmediate(V0, reinterpret_cast<uword>(isolate)); | 1787 __ LoadImmediate(V0, reinterpret_cast<uword>(isolate)); |
| 1788 // Set return value. | 1788 // Set return value. |
| 1789 __ Ret(); | 1789 __ Ret(); |
| 1790 __ delay_slot()->lw(V0, Address(V0, Isolate::current_tag_offset())); | 1790 __ delay_slot()->lw(V0, Address(V0, Isolate::current_tag_offset())); |
| 1791 } | 1791 } |
| 1792 | 1792 |
| 1793 } // namespace dart | 1793 } // namespace dart |
| 1794 | 1794 |
| 1795 #endif // defined TARGET_ARCH_MIPS | 1795 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |