| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
| 9 | 9 |
| 10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 #include "vm/symbols.h" | 14 #include "vm/symbols.h" |
| 15 | 15 |
| 16 namespace dart { | 16 namespace dart { |
| 17 | 17 |
| 18 DECLARE_FLAG(bool, enable_type_checks); | 18 DECLARE_FLAG(bool, enable_type_checks); |
| 19 | 19 |
| 20 #define __ assembler-> | 20 #define __ assembler-> |
| 21 | 21 |
| 22 | 22 |
| 23 void Intrinsifier::Array_getLength(Assembler* assembler) { | 23 void Intrinsifier::ObjectArrayLength(Assembler* assembler) { |
| 24 __ ldr(R0, Address(SP, 0 * kWordSize)); | 24 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 25 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 25 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 26 __ ret(); | 26 __ ret(); |
| 27 } | 27 } |
| 28 | 28 |
| 29 | 29 |
| 30 void Intrinsifier::ImmutableList_getLength(Assembler* assembler) { | 30 void Intrinsifier::ImmutableArrayLength(Assembler* assembler) { |
| 31 Array_getLength(assembler); | 31 ObjectArrayLength(assembler); |
| 32 } | 32 } |
| 33 | 33 |
| 34 | 34 |
| 35 void Intrinsifier::Array_getIndexed(Assembler* assembler) { | 35 void Intrinsifier::ObjectArrayGetIndexed(Assembler* assembler) { |
| 36 Label fall_through; | 36 Label fall_through; |
| 37 | 37 |
| 38 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 38 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 39 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 39 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 40 | 40 |
| 41 __ tsti(R0, kSmiTagMask); | 41 __ tsti(R0, kSmiTagMask); |
| 42 __ b(&fall_through, NE); // Index is not an smi, fall through. | 42 __ b(&fall_through, NE); // Index is not an smi, fall through. |
| 43 | 43 |
| 44 // Range check. | 44 // Range check. |
| 45 __ ldr(R6, FieldAddress(R1, Array::length_offset())); | 45 __ ldr(R6, FieldAddress(R1, Array::length_offset())); |
| 46 __ cmp(R0, Operand(R6)); | 46 __ cmp(R0, Operand(R6)); |
| 47 __ b(&fall_through, CS); | 47 __ b(&fall_through, CS); |
| 48 | 48 |
| 49 ASSERT(kSmiTagShift == 1); | 49 ASSERT(kSmiTagShift == 1); |
| 50 // array element at R1 + R0*4 + Array::data_offset - 1 | 50 // array element at R1 + R0*4 + Array::data_offset - 1 |
| 51 __ add(R6, R1, Operand(R0, LSL, 2)); | 51 __ add(R6, R1, Operand(R0, LSL, 2)); |
| 52 __ ldr(R0, FieldAddress(R6, Array::data_offset())); | 52 __ ldr(R0, FieldAddress(R6, Array::data_offset())); |
| 53 __ ret(); | 53 __ ret(); |
| 54 __ Bind(&fall_through); | 54 __ Bind(&fall_through); |
| 55 } | 55 } |
| 56 | 56 |
| 57 | 57 |
| 58 void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) { | 58 void Intrinsifier::ImmutableArrayGetIndexed(Assembler* assembler) { |
| 59 Array_getIndexed(assembler); | 59 ObjectArrayGetIndexed(assembler); |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 63 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 64 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 64 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 65 const Class& cls = Class::Handle( | 65 const Class& cls = Class::Handle( |
| 66 core_lib.LookupClassAllowPrivate(Symbols::_List())); | 66 core_lib.LookupClassAllowPrivate(Symbols::_List())); |
| 67 ASSERT(!cls.IsNull()); | 67 ASSERT(!cls.IsNull()); |
| 68 ASSERT(cls.NumTypeArguments() == 1); | 68 ASSERT(cls.NumTypeArguments() == 1); |
| 69 const intptr_t field_offset = cls.type_arguments_field_offset(); | 69 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 70 ASSERT(field_offset != Class::kNoTypeArguments); | 70 ASSERT(field_offset != Class::kNoTypeArguments); |
| 71 return field_offset; | 71 return field_offset; |
| 72 } | 72 } |
| 73 | 73 |
| 74 | 74 |
| 75 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 75 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
| 76 // update. Array length is always a Smi. | 76 // update. Array length is always a Smi. |
| 77 void Intrinsifier::Array_setIndexed(Assembler* assembler) { | 77 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) { |
| 78 Label fall_through; | 78 Label fall_through; |
| 79 | 79 |
| 80 if (FLAG_enable_type_checks) { | 80 if (FLAG_enable_type_checks) { |
| 81 const intptr_t type_args_field_offset = | 81 const intptr_t type_args_field_offset = |
| 82 ComputeObjectArrayTypeArgumentsOffset(); | 82 ComputeObjectArrayTypeArgumentsOffset(); |
| 83 // Inline simple tests (Smi, null), fallthrough if not positive. | 83 // Inline simple tests (Smi, null), fallthrough if not positive. |
| 84 Label checked_ok; | 84 Label checked_ok; |
| 85 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 85 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 86 | 86 |
| 87 // Null value is valid for any type. | 87 // Null value is valid for any type. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 FieldAddress(R1, Array::data_offset()), | 130 FieldAddress(R1, Array::data_offset()), |
| 131 R2); | 131 R2); |
| 132 // Caller is responsible for preserving the value if necessary. | 132 // Caller is responsible for preserving the value if necessary. |
| 133 __ ret(); | 133 __ ret(); |
| 134 __ Bind(&fall_through); | 134 __ Bind(&fall_through); |
| 135 } | 135 } |
| 136 | 136 |
| 137 | 137 |
| 138 // Allocate a GrowableObjectArray using the backing array specified. | 138 // Allocate a GrowableObjectArray using the backing array specified. |
| 139 // On stack: type argument (+1), data (+0). | 139 // On stack: type argument (+1), data (+0). |
| 140 void Intrinsifier::GrowableList_Allocate(Assembler* assembler) { | 140 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 141 // The newly allocated object is returned in R0. | 141 // The newly allocated object is returned in R0. |
| 142 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 142 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 143 const intptr_t kArrayOffset = 0 * kWordSize; | 143 const intptr_t kArrayOffset = 0 * kWordSize; |
| 144 Label fall_through; | 144 Label fall_through; |
| 145 | 145 |
| 146 // Try allocating in new space. | 146 // Try allocating in new space. |
| 147 const Class& cls = Class::Handle( | 147 const Class& cls = Class::Handle( |
| 148 Isolate::Current()->object_store()->growable_object_array_class()); | 148 Isolate::Current()->object_store()->growable_object_array_class()); |
| 149 __ TryAllocate(cls, &fall_through, R0, R1, kNoPP); | 149 __ TryAllocate(cls, &fall_through, R0, R1, kNoPP); |
| 150 | 150 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 166 | 166 |
| 167 // Set the length field in the growable array object to 0. | 167 // Set the length field in the growable array object to 0. |
| 168 __ LoadImmediate(R1, 0, kNoPP); | 168 __ LoadImmediate(R1, 0, kNoPP); |
| 169 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 169 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 170 __ ret(); // Returns the newly allocated object in R0. | 170 __ ret(); // Returns the newly allocated object in R0. |
| 171 | 171 |
| 172 __ Bind(&fall_through); | 172 __ Bind(&fall_through); |
| 173 } | 173 } |
| 174 | 174 |
| 175 | 175 |
| 176 void Intrinsifier::GrowableList_getLength(Assembler* assembler) { | 176 void Intrinsifier::GrowableArrayLength(Assembler* assembler) { |
| 177 __ ldr(R0, Address(SP, 0 * kWordSize)); | 177 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 178 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); | 178 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 179 __ ret(); | 179 __ ret(); |
| 180 } | 180 } |
| 181 | 181 |
| 182 | 182 |
| 183 void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) { | 183 void Intrinsifier::GrowableArrayCapacity(Assembler* assembler) { |
| 184 __ ldr(R0, Address(SP, 0 * kWordSize)); | 184 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 185 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); | 185 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); |
| 186 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 186 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 187 __ ret(); | 187 __ ret(); |
| 188 } | 188 } |
| 189 | 189 |
| 190 | 190 |
| 191 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { | 191 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { |
| 192 Label fall_through; | 192 Label fall_through; |
| 193 | 193 |
| 194 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 194 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 195 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 195 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 196 | 196 |
| 197 __ tsti(R0, kSmiTagMask); | 197 __ tsti(R0, kSmiTagMask); |
| 198 __ b(&fall_through, NE); // Index is not an smi, fall through. | 198 __ b(&fall_through, NE); // Index is not an smi, fall through. |
| 199 | 199 |
| 200 // Range check. | 200 // Range check. |
| 201 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); | 201 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); |
| 202 __ cmp(R0, Operand(R6)); | 202 __ cmp(R0, Operand(R6)); |
| 203 __ b(&fall_through, CS); | 203 __ b(&fall_through, CS); |
| 204 | 204 |
| 205 ASSERT(kSmiTagShift == 1); | 205 ASSERT(kSmiTagShift == 1); |
| 206 // array element at R6 + R0 * 4 + Array::data_offset - 1 | 206 // array element at R6 + R0 * 4 + Array::data_offset - 1 |
| 207 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset())); // Data | 207 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset())); // Data |
| 208 __ add(R6, R6, Operand(R0, LSL, 2)); | 208 __ add(R6, R6, Operand(R0, LSL, 2)); |
| 209 __ ldr(R0, FieldAddress(R6, Array::data_offset())); | 209 __ ldr(R0, FieldAddress(R6, Array::data_offset())); |
| 210 __ ret(); | 210 __ ret(); |
| 211 __ Bind(&fall_through); | 211 __ Bind(&fall_through); |
| 212 } | 212 } |
| 213 | 213 |
| 214 | 214 |
| 215 // Set value into growable object array at specified index. | 215 // Set value into growable object array at specified index. |
| 216 // On stack: growable array (+2), index (+1), value (+0). | 216 // On stack: growable array (+2), index (+1), value (+0). |
| 217 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { | 217 void Intrinsifier::GrowableArraySetIndexed(Assembler* assembler) { |
| 218 if (FLAG_enable_type_checks) { | 218 if (FLAG_enable_type_checks) { |
| 219 return; | 219 return; |
| 220 } | 220 } |
| 221 Label fall_through; | 221 Label fall_through; |
| 222 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 222 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 223 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. | 223 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 224 __ tsti(R1, kSmiTagMask); | 224 __ tsti(R1, kSmiTagMask); |
| 225 __ b(&fall_through, NE); // Non-smi index. | 225 __ b(&fall_through, NE); // Non-smi index. |
| 226 // Range check using _length field. | 226 // Range check using _length field. |
| 227 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); | 227 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 228 __ cmp(R1, Operand(R2)); | 228 __ cmp(R1, Operand(R2)); |
| 229 // Runtime throws exception. | 229 // Runtime throws exception. |
| 230 __ b(&fall_through, CS); | 230 __ b(&fall_through, CS); |
| 231 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. | 231 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. |
| 232 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 232 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 233 // Note that R1 is Smi, i.e, times 2. | 233 // Note that R1 is Smi, i.e, times 2. |
| 234 ASSERT(kSmiTagShift == 1); | 234 ASSERT(kSmiTagShift == 1); |
| 235 __ add(R1, R0, Operand(R1, LSL, 2)); | 235 __ add(R1, R0, Operand(R1, LSL, 2)); |
| 236 __ StoreIntoObject(R0, | 236 __ StoreIntoObject(R0, |
| 237 FieldAddress(R1, Array::data_offset()), | 237 FieldAddress(R1, Array::data_offset()), |
| 238 R2); | 238 R2); |
| 239 __ ret(); | 239 __ ret(); |
| 240 __ Bind(&fall_through); | 240 __ Bind(&fall_through); |
| 241 } | 241 } |
| 242 | 242 |
| 243 | 243 |
| 244 // Set length of growable object array. The length cannot | 244 // Set length of growable object array. The length cannot |
| 245 // be greater than the length of the data container. | 245 // be greater than the length of the data container. |
| 246 // On stack: growable array (+1), length (+0). | 246 // On stack: growable array (+1), length (+0). |
| 247 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { | 247 void Intrinsifier::GrowableArraySetLength(Assembler* assembler) { |
| 248 Label fall_through; | 248 Label fall_through; |
| 249 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 249 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 250 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. | 250 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. |
| 251 __ tsti(R1, kSmiTagMask); // Check for Smi. | 251 __ tsti(R1, kSmiTagMask); // Check for Smi. |
| 252 __ b(&fall_through, NE); | 252 __ b(&fall_through, NE); |
| 253 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 253 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 254 __ ret(); | 254 __ ret(); |
| 255 __ Bind(&fall_through); | 255 __ Bind(&fall_through); |
| 256 // Fall through on non-Smi. | 256 // Fall through on non-Smi. |
| 257 } | 257 } |
| 258 | 258 |
| 259 | 259 |
| 260 // Set data of growable object array. | 260 // Set data of growable object array. |
| 261 // On stack: growable array (+1), data (+0). | 261 // On stack: growable array (+1), data (+0). |
| 262 void Intrinsifier::GrowableList_setData(Assembler* assembler) { | 262 void Intrinsifier::GrowableArraySetData(Assembler* assembler) { |
| 263 if (FLAG_enable_type_checks) { | 263 if (FLAG_enable_type_checks) { |
| 264 return; | 264 return; |
| 265 } | 265 } |
| 266 Label fall_through; | 266 Label fall_through; |
| 267 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. | 267 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. |
| 268 // Check that data is an ObjectArray. | 268 // Check that data is an ObjectArray. |
| 269 __ tsti(R1, kSmiTagMask); | 269 __ tsti(R1, kSmiTagMask); |
| 270 __ b(&fall_through, EQ); // Data is Smi. | 270 __ b(&fall_through, EQ); // Data is Smi. |
| 271 __ CompareClassId(R1, kArrayCid, kNoPP); | 271 __ CompareClassId(R1, kArrayCid, kNoPP); |
| 272 __ b(&fall_through, NE); | 272 __ b(&fall_through, NE); |
| 273 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 273 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 274 __ StoreIntoObject(R0, | 274 __ StoreIntoObject(R0, |
| 275 FieldAddress(R0, GrowableObjectArray::data_offset()), | 275 FieldAddress(R0, GrowableObjectArray::data_offset()), |
| 276 R1); | 276 R1); |
| 277 __ ret(); | 277 __ ret(); |
| 278 __ Bind(&fall_through); | 278 __ Bind(&fall_through); |
| 279 } | 279 } |
| 280 | 280 |
| 281 | 281 |
| 282 // Add an element to growable array if it doesn't need to grow, otherwise | 282 // Add an element to growable array if it doesn't need to grow, otherwise |
| 283 // call into regular code. | 283 // call into regular code. |
| 284 // On stack: growable array (+1), value (+0). | 284 // On stack: growable array (+1), value (+0). |
| 285 void Intrinsifier::GrowableList_add(Assembler* assembler) { | 285 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
| 286 // In checked mode we need to type-check the incoming argument. | 286 // In checked mode we need to type-check the incoming argument. |
| 287 if (FLAG_enable_type_checks) { | 287 if (FLAG_enable_type_checks) { |
| 288 return; | 288 return; |
| 289 } | 289 } |
| 290 Label fall_through; | 290 Label fall_through; |
| 291 // R0: Array. | 291 // R0: Array. |
| 292 __ ldr(R0, Address(SP, 1 * kWordSize)); | 292 __ ldr(R0, Address(SP, 1 * kWordSize)); |
| 293 // R1: length. | 293 // R1: length. |
| 294 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 294 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 295 // R2: data. | 295 // R2: data. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 309 __ StoreIntoObject(R2, | 309 __ StoreIntoObject(R2, |
| 310 FieldAddress(R1, Array::data_offset()), | 310 FieldAddress(R1, Array::data_offset()), |
| 311 R0); | 311 R0); |
| 312 __ LoadObject(R0, Object::null_object(), PP); | 312 __ LoadObject(R0, Object::null_object(), PP); |
| 313 __ ret(); | 313 __ ret(); |
| 314 __ Bind(&fall_through); | 314 __ Bind(&fall_through); |
| 315 } | 315 } |
| 316 | 316 |
| 317 | 317 |
| 318 // Gets the length of a TypedData. | 318 // Gets the length of a TypedData. |
| 319 void Intrinsifier::TypedData_getLength(Assembler* assembler) { | 319 void Intrinsifier::TypedDataLength(Assembler* assembler) { |
| 320 __ ldr(R0, Address(SP, 0 * kWordSize)); | 320 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 321 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); | 321 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); |
| 322 __ ret(); | 322 __ ret(); |
| 323 } | 323 } |
| 324 | 324 |
| 325 | 325 |
| 326 void Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) { | 326 void Intrinsifier::Uint8ArrayGetIndexed(Assembler* assembler) { |
| 327 Label fall_through; | 327 Label fall_through; |
| 328 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | 328 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. |
| 329 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | 329 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. |
| 330 __ tsti(R0, kSmiTagMask); | 330 __ tsti(R0, kSmiTagMask); |
| 331 __ b(&fall_through, NE); // Index is not a smi, fall through. | 331 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 332 | 332 |
| 333 // Range check. | 333 // Range check. |
| 334 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | 334 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); |
| 335 __ cmp(R0, Operand(R6)); | 335 __ cmp(R0, Operand(R6)); |
| 336 __ b(&fall_through, CS); | 336 __ b(&fall_through, CS); |
| 337 | 337 |
| 338 // Array element at R1 + R0 + TypedData::data_offset - 1. | 338 // Array element at R1 + R0 + TypedData::data_offset - 1. |
| 339 // Untag R0. | 339 // Untag R0. |
| 340 __ add(R1, R1, Operand(R0, LSR, 1)); | 340 __ add(R1, R1, Operand(R0, LSR, 1)); |
| 341 __ ldr(R0, FieldAddress(R1, TypedData::data_offset()), kUnsignedByte); | 341 __ ldr(R0, FieldAddress(R1, TypedData::data_offset()), kUnsignedByte); |
| 342 __ SmiTag(R0); | 342 __ SmiTag(R0); |
| 343 __ ret(); | 343 __ ret(); |
| 344 __ Bind(&fall_through); | 344 __ Bind(&fall_through); |
| 345 } | 345 } |
| 346 | 346 |
| 347 | 347 |
| 348 void Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) { | 348 void Intrinsifier::ExternalUint8ArrayGetIndexed(Assembler* assembler) { |
| 349 Label fall_through; | 349 Label fall_through; |
| 350 | 350 |
| 351 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | 351 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. |
| 352 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | 352 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. |
| 353 __ tsti(R0, kSmiTagMask); | 353 __ tsti(R0, kSmiTagMask); |
| 354 __ b(&fall_through, NE); // Index is not a smi, fall through. | 354 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 355 | 355 |
| 356 // Range check. | 356 // Range check. |
| 357 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | 357 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); |
| 358 __ cmp(R0, Operand(R6)); | 358 __ cmp(R0, Operand(R6)); |
| 359 __ b(&fall_through, CS); | 359 __ b(&fall_through, CS); |
| 360 | 360 |
| 361 __ ldr(R1, FieldAddress(R1, ExternalTypedData::data_offset())); | 361 __ ldr(R1, FieldAddress(R1, ExternalTypedData::data_offset())); |
| 362 | 362 |
| 363 // Untag R0. | 363 // Untag R0. |
| 364 __ add(R1, R1, Operand(R0, LSR, 1)); | 364 __ add(R1, R1, Operand(R0, LSR, 1)); |
| 365 __ ldr(R0, Address(R1, 0), kUnsignedByte); | 365 __ ldr(R0, Address(R1, 0), kUnsignedByte); |
| 366 __ SmiTag(R0); | 366 __ SmiTag(R0); |
| 367 __ ret(); | 367 __ ret(); |
| 368 __ Bind(&fall_through); | 368 __ Bind(&fall_through); |
| 369 } | 369 } |
| 370 | 370 |
| 371 | 371 |
| 372 void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) { | 372 void Intrinsifier::Float64ArrayGetIndexed(Assembler* assembler) { |
| 373 Label fall_through; | 373 Label fall_through; |
| 374 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. | 374 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index. |
| 375 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. | 375 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array. |
| 376 __ tsti(R0, kSmiTagMask); | 376 __ tsti(R0, kSmiTagMask); |
| 377 __ b(&fall_through, NE); // Index is not a smi, fall through. | 377 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 378 | 378 |
| 379 // Range check. | 379 // Range check. |
| 380 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | 380 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); |
| 381 __ cmp(R0, Operand(R6)); | 381 __ cmp(R0, Operand(R6)); |
| 382 __ b(&fall_through, CS); | 382 __ b(&fall_through, CS); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 397 &fall_through, | 397 &fall_through, |
| 398 R0, // Result register. | 398 R0, // Result register. |
| 399 R1, // Temp register. | 399 R1, // Temp register. |
| 400 kNoPP); | 400 kNoPP); |
| 401 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); | 401 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); |
| 402 __ ret(); | 402 __ ret(); |
| 403 __ Bind(&fall_through); | 403 __ Bind(&fall_through); |
| 404 } | 404 } |
| 405 | 405 |
| 406 | 406 |
| 407 void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) { | 407 void Intrinsifier::Float64ArraySetIndexed(Assembler* assembler) { |
| 408 Label fall_through; | 408 Label fall_through; |
| 409 __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index. | 409 __ ldr(R0, Address(SP, + 1 * kWordSize)); // Index. |
| 410 __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array. | 410 __ ldr(R1, Address(SP, + 2 * kWordSize)); // Array. |
| 411 __ tsti(R0, kSmiTagMask); | 411 __ tsti(R0, kSmiTagMask); |
| 412 __ b(&fall_through, NE); // Index is not a smi, fall through. | 412 __ b(&fall_through, NE); // Index is not a smi, fall through. |
| 413 | 413 |
| 414 // Range check. | 414 // Range check. |
| 415 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); | 415 __ ldr(R6, FieldAddress(R1, TypedData::length_offset())); |
| 416 __ cmp(R0, Operand(R6)); | 416 __ cmp(R0, Operand(R6)); |
| 417 __ b(&fall_through, CS); | 417 __ b(&fall_through, CS); |
| (...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1146 __ Bind(&is_zero); | 1146 __ Bind(&is_zero); |
| 1147 // Check for negative zero by looking at the sign bit. | 1147 // Check for negative zero by looking at the sign bit. |
| 1148 __ fmovrd(R1, V0); | 1148 __ fmovrd(R1, V0); |
| 1149 __ Lsr(R1, R1, 63); | 1149 __ Lsr(R1, R1, 63); |
| 1150 __ tsti(R1, 1); | 1150 __ tsti(R1, 1); |
| 1151 __ csel(R0, true_reg, false_reg, NE); // Sign bit set. | 1151 __ csel(R0, true_reg, false_reg, NE); // Sign bit set. |
| 1152 __ ret(); | 1152 __ ret(); |
| 1153 } | 1153 } |
| 1154 | 1154 |
| 1155 | 1155 |
| 1156 void Intrinsifier::Double_toInt(Assembler* assembler) { | 1156 void Intrinsifier::DoubleToInteger(Assembler* assembler) { |
| 1157 Label fall_through; | 1157 Label fall_through; |
| 1158 | 1158 |
| 1159 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1159 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1160 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); | 1160 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); |
| 1161 | 1161 |
| 1162 // Explicit NaN check, since ARM gives an FPU exception if you try to | 1162 // Explicit NaN check, since ARM gives an FPU exception if you try to |
| 1163 // convert NaN to an int. | 1163 // convert NaN to an int. |
| 1164 __ fcmpd(V0, V0); | 1164 __ fcmpd(V0, V0); |
| 1165 __ b(&fall_through, VS); | 1165 __ b(&fall_through, VS); |
| 1166 | 1166 |
| 1167 __ fcvtzds(R0, V0); | 1167 __ fcvtzds(R0, V0); |
| 1168 // Overflow is signaled with minint. | 1168 // Overflow is signaled with minint. |
| 1169 // Check for overflow and that it fits into Smi. | 1169 // Check for overflow and that it fits into Smi. |
| 1170 __ CompareImmediate(R0, 0xC000000000000000, kNoPP); | 1170 __ CompareImmediate(R0, 0xC000000000000000, kNoPP); |
| 1171 __ b(&fall_through, MI); | 1171 __ b(&fall_through, MI); |
| 1172 __ SmiTag(R0); | 1172 __ SmiTag(R0); |
| 1173 __ ret(); | 1173 __ ret(); |
| 1174 __ Bind(&fall_through); | 1174 __ Bind(&fall_through); |
| 1175 } | 1175 } |
| 1176 | 1176 |
| 1177 | 1177 |
| 1178 void Intrinsifier::Math_sqrt(Assembler* assembler) { | 1178 void Intrinsifier::MathSqrt(Assembler* assembler) { |
| 1179 Label fall_through, is_smi, double_op; | 1179 Label fall_through, is_smi, double_op; |
| 1180 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1180 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1181 // Argument is double and is in R0. | 1181 // Argument is double and is in R0. |
| 1182 __ LoadDFieldFromOffset(V1, R0, Double::value_offset(), kNoPP); | 1182 __ LoadDFieldFromOffset(V1, R0, Double::value_offset(), kNoPP); |
| 1183 __ Bind(&double_op); | 1183 __ Bind(&double_op); |
| 1184 __ fsqrtd(V0, V1); | 1184 __ fsqrtd(V0, V1); |
| 1185 const Class& double_class = Class::Handle( | 1185 const Class& double_class = Class::Handle( |
| 1186 Isolate::Current()->object_store()->double_class()); | 1186 Isolate::Current()->object_store()->double_class()); |
| 1187 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); | 1187 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); |
| 1188 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); | 1188 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1225 __ LoadFromOffset(R2, R1, disp, kNoPP); | 1225 __ LoadFromOffset(R2, R1, disp, kNoPP); |
| 1226 __ Lsr(R3, R2, 32); | 1226 __ Lsr(R3, R2, 32); |
| 1227 __ andi(R2, R2, 0xffffffff); | 1227 __ andi(R2, R2, 0xffffffff); |
| 1228 __ mul(R2, R0, R2); | 1228 __ mul(R2, R0, R2); |
| 1229 __ add(R2, R2, Operand(R3)); | 1229 __ add(R2, R2, Operand(R3)); |
| 1230 __ StoreToOffset(R2, R1, disp, kNoPP); | 1230 __ StoreToOffset(R2, R1, disp, kNoPP); |
| 1231 __ ret(); | 1231 __ ret(); |
| 1232 } | 1232 } |
| 1233 | 1233 |
| 1234 | 1234 |
| 1235 void Intrinsifier::Object_equal(Assembler* assembler) { | 1235 void Intrinsifier::ObjectEquals(Assembler* assembler) { |
| 1236 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1236 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1237 __ ldr(R1, Address(SP, 1 * kWordSize)); | 1237 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| 1238 __ cmp(R0, Operand(R1)); | 1238 __ cmp(R0, Operand(R1)); |
| 1239 __ LoadObject(R0, Bool::False(), PP); | 1239 __ LoadObject(R0, Bool::False(), PP); |
| 1240 __ LoadObject(TMP, Bool::True(), PP); | 1240 __ LoadObject(TMP, Bool::True(), PP); |
| 1241 __ csel(R0, TMP, R0, EQ); | 1241 __ csel(R0, TMP, R0, EQ); |
| 1242 __ ret(); | 1242 __ ret(); |
| 1243 } | 1243 } |
| 1244 | 1244 |
| 1245 | 1245 |
| 1246 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1246 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1247 Label fall_through; | 1247 Label fall_through; |
| 1248 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1248 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1249 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | 1249 __ ldr(R0, FieldAddress(R0, String::hash_offset())); |
| 1250 __ CompareRegisters(R0, ZR); | 1250 __ CompareRegisters(R0, ZR); |
| 1251 __ b(&fall_through, EQ); | 1251 __ b(&fall_through, EQ); |
| 1252 __ ret(); | 1252 __ ret(); |
| 1253 // Hash not yet computed. | 1253 // Hash not yet computed. |
| 1254 __ Bind(&fall_through); | 1254 __ Bind(&fall_through); |
| 1255 } | 1255 } |
| 1256 | 1256 |
| 1257 | 1257 |
| 1258 void Intrinsifier::String_getLength(Assembler* assembler) { | 1258 void Intrinsifier::StringBaseLength(Assembler* assembler) { |
| 1259 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1259 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1260 __ ldr(R0, FieldAddress(R0, String::length_offset())); | 1260 __ ldr(R0, FieldAddress(R0, String::length_offset())); |
| 1261 __ ret(); | 1261 __ ret(); |
| 1262 } | 1262 } |
| 1263 | 1263 |
| 1264 | 1264 |
| 1265 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1265 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { |
| 1266 Label fall_through, try_two_byte_string; | 1266 Label fall_through, try_two_byte_string; |
| 1267 | 1267 |
| 1268 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1268 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1269 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1269 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1270 __ tsti(R1, kSmiTagMask); | 1270 __ tsti(R1, kSmiTagMask); |
| 1271 __ b(&fall_through, NE); // Index is not a Smi. | 1271 __ b(&fall_through, NE); // Index is not a Smi. |
| 1272 // Range check. | 1272 // Range check. |
| 1273 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1273 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1274 __ cmp(R1, Operand(R2)); | 1274 __ cmp(R1, Operand(R2)); |
| 1275 __ b(&fall_through, CS); // Runtime throws exception. | 1275 __ b(&fall_through, CS); // Runtime throws exception. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1287 ASSERT(kSmiTagShift == 1); | 1287 ASSERT(kSmiTagShift == 1); |
| 1288 __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag, kNoPP); | 1288 __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag, kNoPP); |
| 1289 __ ldr(R0, Address(R0, R1), kUnsignedHalfword); | 1289 __ ldr(R0, Address(R0, R1), kUnsignedHalfword); |
| 1290 __ SmiTag(R0); | 1290 __ SmiTag(R0); |
| 1291 __ ret(); | 1291 __ ret(); |
| 1292 | 1292 |
| 1293 __ Bind(&fall_through); | 1293 __ Bind(&fall_through); |
| 1294 } | 1294 } |
| 1295 | 1295 |
| 1296 | 1296 |
| 1297 void Intrinsifier::String_getIsEmpty(Assembler* assembler) { | 1297 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
| 1298 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1298 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1299 __ ldr(R0, FieldAddress(R0, String::length_offset())); | 1299 __ ldr(R0, FieldAddress(R0, String::length_offset())); |
| 1300 __ cmp(R0, Operand(Smi::RawValue(0))); | 1300 __ cmp(R0, Operand(Smi::RawValue(0))); |
| 1301 __ LoadObject(R0, Bool::True(), PP); | 1301 __ LoadObject(R0, Bool::True(), PP); |
| 1302 __ LoadObject(TMP, Bool::False(), PP); | 1302 __ LoadObject(TMP, Bool::False(), PP); |
| 1303 __ csel(R0, TMP, R0, NE); | 1303 __ csel(R0, TMP, R0, NE); |
| 1304 __ ret(); | 1304 __ ret(); |
| 1305 } | 1305 } |
| 1306 | 1306 |
| 1307 | 1307 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1495 __ str(R1, FieldAddress(R7, OneByteString::data_offset()), kUnsignedByte); | 1495 __ str(R1, FieldAddress(R7, OneByteString::data_offset()), kUnsignedByte); |
| 1496 __ AddImmediate(R7, R7, 1, kNoPP); | 1496 __ AddImmediate(R7, R7, 1, kNoPP); |
| 1497 __ b(&loop, GT); | 1497 __ b(&loop, GT); |
| 1498 | 1498 |
| 1499 __ Bind(&done); | 1499 __ Bind(&done); |
| 1500 __ ret(); | 1500 __ ret(); |
| 1501 __ Bind(&fall_through); | 1501 __ Bind(&fall_through); |
| 1502 } | 1502 } |
| 1503 | 1503 |
| 1504 | 1504 |
| 1505 void Intrinsifier::OneByteString_setAt(Assembler* assembler) { | 1505 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { |
| 1506 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 1506 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 1507 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 1507 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 1508 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString. | 1508 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString. |
| 1509 __ SmiUntag(R1); | 1509 __ SmiUntag(R1); |
| 1510 __ SmiUntag(R2); | 1510 __ SmiUntag(R2); |
| 1511 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); | 1511 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); |
| 1512 __ str(R2, Address(R3, R1), kUnsignedByte); | 1512 __ str(R2, Address(R3, R1), kUnsignedByte); |
| 1513 __ ret(); | 1513 __ ret(); |
| 1514 } | 1514 } |
| 1515 | 1515 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1636 Isolate* isolate = Isolate::Current(); | 1636 Isolate* isolate = Isolate::Current(); |
| 1637 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); | 1637 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); |
| 1638 // Set return value to Isolate::current_tag_. | 1638 // Set return value to Isolate::current_tag_. |
| 1639 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); | 1639 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); |
| 1640 __ ret(); | 1640 __ ret(); |
| 1641 } | 1641 } |
| 1642 | 1642 |
| 1643 } // namespace dart | 1643 } // namespace dart |
| 1644 | 1644 |
| 1645 #endif // defined TARGET_ARCH_ARM64 | 1645 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |