| 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 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 __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length. | 31 __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length. |
| 32 | 32 |
| 33 // Check that length is a positive Smi. | 33 // Check that length is a positive Smi. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 116 |
| 117 Label init_loop; | 117 Label init_loop; |
| 118 __ Bind(&init_loop); | 118 __ Bind(&init_loop); |
| 119 __ cmp(R2, ShifterOperand(R1)); | 119 __ cmp(R2, ShifterOperand(R1)); |
| 120 __ str(R3, Address(R2, 0), CC); | 120 __ str(R3, Address(R2, 0), CC); |
| 121 __ AddImmediate(R2, kWordSize, CC); | 121 __ AddImmediate(R2, kWordSize, CC); |
| 122 __ b(&init_loop, CC); | 122 __ b(&init_loop, CC); |
| 123 | 123 |
| 124 __ Ret(); // Returns the newly allocated object in R0. | 124 __ Ret(); // Returns the newly allocated object in R0. |
| 125 __ Bind(&fall_through); | 125 __ Bind(&fall_through); |
| 126 return false; | |
| 127 } | 126 } |
| 128 | 127 |
| 129 | 128 |
| 130 bool Intrinsifier::Array_getLength(Assembler* assembler) { | 129 void Intrinsifier::Array_getLength(Assembler* assembler) { |
| 131 __ ldr(R0, Address(SP, 0 * kWordSize)); | 130 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 132 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 131 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 133 __ Ret(); | 132 __ Ret(); |
| 134 return true; | |
| 135 } | 133 } |
| 136 | 134 |
| 137 | 135 |
| 138 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { | 136 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { |
| 139 return Array_getLength(assembler); | 137 return Array_getLength(assembler); |
| 140 } | 138 } |
| 141 | 139 |
| 142 | 140 |
| 143 bool Intrinsifier::Array_getIndexed(Assembler* assembler) { | 141 void Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 144 Label fall_through; | 142 Label fall_through; |
| 145 | 143 |
| 146 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 144 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 147 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 145 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 148 | 146 |
| 149 __ tst(R0, ShifterOperand(kSmiTagMask)); | 147 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 150 __ b(&fall_through, NE); // Index is not an smi, fall through | 148 __ b(&fall_through, NE); // Index is not an smi, fall through |
| 151 | 149 |
| 152 // range check | 150 // range check |
| 153 __ ldr(R6, FieldAddress(R1, Array::length_offset())); | 151 __ ldr(R6, FieldAddress(R1, Array::length_offset())); |
| 154 __ cmp(R0, ShifterOperand(R6)); | 152 __ cmp(R0, ShifterOperand(R6)); |
| 155 | 153 |
| 156 ASSERT(kSmiTagShift == 1); | 154 ASSERT(kSmiTagShift == 1); |
| 157 // array element at R1 + R0*2 + Array::data_offset - 1 | 155 // array element at R1 + R0*2 + Array::data_offset - 1 |
| 158 __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC); | 156 __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC); |
| 159 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); | 157 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); |
| 160 __ bx(LR, CC); | 158 __ bx(LR, CC); |
| 161 __ Bind(&fall_through); | 159 __ Bind(&fall_through); |
| 162 return false; | |
| 163 } | 160 } |
| 164 | 161 |
| 165 | 162 |
| 166 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { | 163 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { |
| 167 return Array_getIndexed(assembler); | 164 return Array_getIndexed(assembler); |
| 168 } | 165 } |
| 169 | 166 |
| 170 | 167 |
| 171 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 168 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 172 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 169 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 173 const Class& cls = Class::Handle( | 170 const Class& cls = Class::Handle( |
| 174 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); | 171 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); |
| 175 ASSERT(!cls.IsNull()); | 172 ASSERT(!cls.IsNull()); |
| 176 ASSERT(cls.HasTypeArguments()); | 173 ASSERT(cls.HasTypeArguments()); |
| 177 ASSERT(cls.NumTypeArguments() == 1); | 174 ASSERT(cls.NumTypeArguments() == 1); |
| 178 const intptr_t field_offset = cls.type_arguments_field_offset(); | 175 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 179 ASSERT(field_offset != Class::kNoTypeArguments); | 176 ASSERT(field_offset != Class::kNoTypeArguments); |
| 180 return field_offset; | 177 return field_offset; |
| 181 } | 178 } |
| 182 | 179 |
| 183 | 180 |
| 184 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 181 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
| 185 // update. Array length is always a Smi. | 182 // update. Array length is always a Smi. |
| 186 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { | 183 void Intrinsifier::Array_setIndexed(Assembler* assembler) { |
| 187 Label fall_through; | 184 Label fall_through; |
| 188 | 185 |
| 189 if (FLAG_enable_type_checks) { | 186 if (FLAG_enable_type_checks) { |
| 190 const intptr_t type_args_field_offset = | 187 const intptr_t type_args_field_offset = |
| 191 ComputeObjectArrayTypeArgumentsOffset(); | 188 ComputeObjectArrayTypeArgumentsOffset(); |
| 192 // Inline simple tests (Smi, null), fallthrough if not positive. | 189 // Inline simple tests (Smi, null), fallthrough if not positive. |
| 193 const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null()); | 190 const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null()); |
| 194 Label checked_ok; | 191 Label checked_ok; |
| 195 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 192 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 196 | 193 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 // Note that R1 is Smi, i.e, times 2. | 235 // Note that R1 is Smi, i.e, times 2. |
| 239 ASSERT(kSmiTagShift == 1); | 236 ASSERT(kSmiTagShift == 1); |
| 240 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 237 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 241 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); // R1 is Smi. | 238 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); // R1 is Smi. |
| 242 __ StoreIntoObject(R0, | 239 __ StoreIntoObject(R0, |
| 243 FieldAddress(R1, Array::data_offset()), | 240 FieldAddress(R1, Array::data_offset()), |
| 244 R2); | 241 R2); |
| 245 // Caller is responsible for preserving the value if necessary. | 242 // Caller is responsible for preserving the value if necessary. |
| 246 __ Ret(); | 243 __ Ret(); |
| 247 __ Bind(&fall_through); | 244 __ Bind(&fall_through); |
| 248 return false; | |
| 249 } | 245 } |
| 250 | 246 |
| 251 | 247 |
| 252 // Allocate a GrowableObjectArray using the backing array specified. | 248 // Allocate a GrowableObjectArray using the backing array specified. |
| 253 // On stack: type argument (+1), data (+0). | 249 // On stack: type argument (+1), data (+0). |
| 254 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 250 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 255 // The newly allocated object is returned in R0. | 251 // The newly allocated object is returned in R0. |
| 256 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; | 252 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
| 257 const intptr_t kArrayOffset = 0 * kWordSize; | 253 const intptr_t kArrayOffset = 0 * kWordSize; |
| 258 Label fall_through; | 254 Label fall_through; |
| 259 | 255 |
| 260 // Compute the size to be allocated, it is based on the array length | 256 // Compute the size to be allocated, it is based on the array length |
| 261 // and is computed as: | 257 // and is computed as: |
| 262 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 258 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| 263 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); | 259 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); |
| 264 | 260 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 R0, | 303 R0, |
| 308 FieldAddress(R0, GrowableObjectArray::type_arguments_offset()), | 304 FieldAddress(R0, GrowableObjectArray::type_arguments_offset()), |
| 309 R1); | 305 R1); |
| 310 | 306 |
| 311 // Set the length field in the growable array object to 0. | 307 // Set the length field in the growable array object to 0. |
| 312 __ LoadImmediate(R1, 0); | 308 __ LoadImmediate(R1, 0); |
| 313 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 309 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 314 __ Ret(); // Returns the newly allocated object in R0. | 310 __ Ret(); // Returns the newly allocated object in R0. |
| 315 | 311 |
| 316 __ Bind(&fall_through); | 312 __ Bind(&fall_through); |
| 317 return false; | |
| 318 } | 313 } |
| 319 | 314 |
| 320 | 315 |
| 321 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 316 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { |
| 322 __ ldr(R0, Address(SP, 0 * kWordSize)); | 317 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 323 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); | 318 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 324 __ Ret(); | 319 __ Ret(); |
| 325 return true; | |
| 326 } | 320 } |
| 327 | 321 |
| 328 | 322 |
| 329 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 323 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { |
| 330 __ ldr(R0, Address(SP, 0 * kWordSize)); | 324 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 331 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); | 325 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); |
| 332 __ ldr(R0, FieldAddress(R0, Array::length_offset())); | 326 __ ldr(R0, FieldAddress(R0, Array::length_offset())); |
| 333 __ Ret(); | 327 __ Ret(); |
| 334 return true; | |
| 335 } | 328 } |
| 336 | 329 |
| 337 | 330 |
| 338 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 331 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { |
| 339 Label fall_through; | 332 Label fall_through; |
| 340 | 333 |
| 341 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 334 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 342 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 335 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 343 | 336 |
| 344 __ tst(R0, ShifterOperand(kSmiTagMask)); | 337 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 345 __ b(&fall_through, NE); // Index is not an smi, fall through | 338 __ b(&fall_through, NE); // Index is not an smi, fall through |
| 346 | 339 |
| 347 // range check | 340 // range check |
| 348 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); | 341 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); |
| 349 __ cmp(R0, ShifterOperand(R6)); | 342 __ cmp(R0, ShifterOperand(R6)); |
| 350 | 343 |
| 351 ASSERT(kSmiTagShift == 1); | 344 ASSERT(kSmiTagShift == 1); |
| 352 // array element at R6 + R0 * 2 + Array::data_offset - 1 | 345 // array element at R6 + R0 * 2 + Array::data_offset - 1 |
| 353 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data | 346 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data |
| 354 __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC); | 347 __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC); |
| 355 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); | 348 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); |
| 356 __ bx(LR, CC); | 349 __ bx(LR, CC); |
| 357 __ Bind(&fall_through); | 350 __ Bind(&fall_through); |
| 358 return false; | |
| 359 } | 351 } |
| 360 | 352 |
| 361 | 353 |
| 362 // Set value into growable object array at specified index. | 354 // Set value into growable object array at specified index. |
| 363 // On stack: growable array (+2), index (+1), value (+0). | 355 // On stack: growable array (+2), index (+1), value (+0). |
| 364 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 356 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { |
| 365 if (FLAG_enable_type_checks) { | 357 if (FLAG_enable_type_checks) { |
| 366 return false; | 358 return; |
| 367 } | 359 } |
| 368 Label fall_through; | 360 Label fall_through; |
| 369 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 361 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 370 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. | 362 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 371 __ tst(R1, ShifterOperand(kSmiTagMask)); | 363 __ tst(R1, ShifterOperand(kSmiTagMask)); |
| 372 __ b(&fall_through, NE); // Non-smi index. | 364 __ b(&fall_through, NE); // Non-smi index. |
| 373 // Range check using _length field. | 365 // Range check using _length field. |
| 374 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); | 366 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 375 __ cmp(R1, ShifterOperand(R2)); | 367 __ cmp(R1, ShifterOperand(R2)); |
| 376 // Runtime throws exception. | 368 // Runtime throws exception. |
| 377 __ b(&fall_through, CS); | 369 __ b(&fall_through, CS); |
| 378 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. | 370 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. |
| 379 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 371 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 380 // Note that R1 is Smi, i.e, times 2. | 372 // Note that R1 is Smi, i.e, times 2. |
| 381 ASSERT(kSmiTagShift == 1); | 373 ASSERT(kSmiTagShift == 1); |
| 382 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); | 374 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); |
| 383 __ StoreIntoObject(R0, | 375 __ StoreIntoObject(R0, |
| 384 FieldAddress(R1, Array::data_offset()), | 376 FieldAddress(R1, Array::data_offset()), |
| 385 R2); | 377 R2); |
| 386 __ Ret(); | 378 __ Ret(); |
| 387 __ Bind(&fall_through); | 379 __ Bind(&fall_through); |
| 388 return false; | |
| 389 } | 380 } |
| 390 | 381 |
| 391 | 382 |
| 392 // Set length of growable object array. The length cannot | 383 // Set length of growable object array. The length cannot |
| 393 // be greater than the length of the data container. | 384 // be greater than the length of the data container. |
| 394 // On stack: growable array (+1), length (+0). | 385 // On stack: growable array (+1), length (+0). |
| 395 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 386 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { |
| 396 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 387 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 397 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. | 388 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. |
| 398 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi. | 389 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi. |
| 399 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ); | 390 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ); |
| 400 __ bx(LR, EQ); | 391 __ bx(LR, EQ); |
| 401 // Fall through on non-Smi. | 392 // Fall through on non-Smi. |
| 402 return false; | |
| 403 } | 393 } |
| 404 | 394 |
| 405 | 395 |
| 406 // Set data of growable object array. | 396 // Set data of growable object array. |
| 407 // On stack: growable array (+1), data (+0). | 397 // On stack: growable array (+1), data (+0). |
| 408 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 398 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { |
| 409 if (FLAG_enable_type_checks) { | 399 if (FLAG_enable_type_checks) { |
| 410 return false; | 400 return; |
| 411 } | 401 } |
| 412 Label fall_through; | 402 Label fall_through; |
| 413 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. | 403 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. |
| 414 // Check that data is an ObjectArray. | 404 // Check that data is an ObjectArray. |
| 415 __ tst(R1, ShifterOperand(kSmiTagMask)); | 405 __ tst(R1, ShifterOperand(kSmiTagMask)); |
| 416 __ b(&fall_through, EQ); // Data is Smi. | 406 __ b(&fall_through, EQ); // Data is Smi. |
| 417 __ CompareClassId(R1, kArrayCid, R0); | 407 __ CompareClassId(R1, kArrayCid, R0); |
| 418 __ b(&fall_through, NE); | 408 __ b(&fall_through, NE); |
| 419 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 409 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 420 __ StoreIntoObject(R0, | 410 __ StoreIntoObject(R0, |
| 421 FieldAddress(R0, GrowableObjectArray::data_offset()), | 411 FieldAddress(R0, GrowableObjectArray::data_offset()), |
| 422 R1); | 412 R1); |
| 423 __ Ret(); | 413 __ Ret(); |
| 424 __ Bind(&fall_through); | 414 __ Bind(&fall_through); |
| 425 return false; | |
| 426 } | 415 } |
| 427 | 416 |
| 428 | 417 |
| 429 // Add an element to growable array if it doesn't need to grow, otherwise | 418 // Add an element to growable array if it doesn't need to grow, otherwise |
| 430 // call into regular code. | 419 // call into regular code. |
| 431 // On stack: growable array (+1), value (+0). | 420 // On stack: growable array (+1), value (+0). |
| 432 bool Intrinsifier::GrowableArray_add(Assembler* assembler) { | 421 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
| 433 // In checked mode we need to type-check the incoming argument. | 422 // In checked mode we need to type-check the incoming argument. |
| 434 if (FLAG_enable_type_checks) return false; | 423 if (FLAG_enable_type_checks) return; |
| 435 Label fall_through; | 424 Label fall_through; |
| 436 // R0: Array. | 425 // R0: Array. |
| 437 __ ldr(R0, Address(SP, 1 * kWordSize)); | 426 __ ldr(R0, Address(SP, 1 * kWordSize)); |
| 438 // R1: length. | 427 // R1: length. |
| 439 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 428 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 440 // R2: data. | 429 // R2: data. |
| 441 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset())); | 430 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset())); |
| 442 // R3: capacity. | 431 // R3: capacity. |
| 443 __ ldr(R3, FieldAddress(R2, Array::length_offset())); | 432 __ ldr(R3, FieldAddress(R2, Array::length_offset())); |
| 444 // Compare length with capacity. | 433 // Compare length with capacity. |
| 445 __ cmp(R1, ShifterOperand(R3)); | 434 __ cmp(R1, ShifterOperand(R3)); |
| 446 __ b(&fall_through, EQ); // Must grow data. | 435 __ b(&fall_through, EQ); // Must grow data. |
| 447 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1)); | 436 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1)); |
| 448 // len = len + 1; | 437 // len = len + 1; |
| 449 __ add(R3, R1, ShifterOperand(value_one)); | 438 __ add(R3, R1, ShifterOperand(value_one)); |
| 450 __ str(R3, FieldAddress(R0, GrowableObjectArray::length_offset())); | 439 __ str(R3, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 451 __ ldr(R0, Address(SP, 0 * kWordSize)); // Value. | 440 __ ldr(R0, Address(SP, 0 * kWordSize)); // Value. |
| 452 ASSERT(kSmiTagShift == 1); | 441 ASSERT(kSmiTagShift == 1); |
| 453 __ add(R1, R2, ShifterOperand(R1, LSL, 1)); | 442 __ add(R1, R2, ShifterOperand(R1, LSL, 1)); |
| 454 __ StoreIntoObject(R2, | 443 __ StoreIntoObject(R2, |
| 455 FieldAddress(R1, Array::data_offset()), | 444 FieldAddress(R1, Array::data_offset()), |
| 456 R0); | 445 R0); |
| 457 const int32_t raw_null = reinterpret_cast<int32_t>(Object::null()); | 446 const int32_t raw_null = reinterpret_cast<int32_t>(Object::null()); |
| 458 __ LoadImmediate(R0, raw_null); | 447 __ LoadImmediate(R0, raw_null); |
| 459 __ Ret(); | 448 __ Ret(); |
| 460 __ Bind(&fall_through); | 449 __ Bind(&fall_through); |
| 461 return false; | |
| 462 } | 450 } |
| 463 | 451 |
| 464 | 452 |
| 465 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ | 453 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ |
| 466 Label fall_through; \ | 454 Label fall_through; \ |
| 467 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ | 455 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ |
| 468 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ | 456 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ |
| 469 /* Check that length is a positive Smi. */ \ | 457 /* Check that length is a positive Smi. */ \ |
| 470 /* R2: requested array length argument. */ \ | 458 /* R2: requested array length argument. */ \ |
| 471 __ tst(R2, ShifterOperand(kSmiTagMask)); \ | 459 __ tst(R2, ShifterOperand(kSmiTagMask)); \ |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 __ cmp(R2, ShifterOperand(R1)); \ | 528 __ cmp(R2, ShifterOperand(R1)); \ |
| 541 __ str(R3, Address(R2, 0), CC); \ | 529 __ str(R3, Address(R2, 0), CC); \ |
| 542 __ add(R2, R2, ShifterOperand(kWordSize), CC); \ | 530 __ add(R2, R2, ShifterOperand(kWordSize), CC); \ |
| 543 __ b(&init_loop, CC); \ | 531 __ b(&init_loop, CC); \ |
| 544 \ | 532 \ |
| 545 __ Ret(); \ | 533 __ Ret(); \ |
| 546 __ Bind(&fall_through); \ | 534 __ Bind(&fall_through); \ |
| 547 | 535 |
| 548 | 536 |
| 549 // Gets the length of a TypedData. | 537 // Gets the length of a TypedData. |
| 550 bool Intrinsifier::TypedData_getLength(Assembler* assembler) { | 538 void Intrinsifier::TypedData_getLength(Assembler* assembler) { |
| 551 __ ldr(R0, Address(SP, 0 * kWordSize)); | 539 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 552 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); | 540 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); |
| 553 __ Ret(); | 541 __ Ret(); |
| 554 return true; | |
| 555 } | 542 } |
| 556 | 543 |
| 557 | 544 |
| 558 static int GetScaleFactor(intptr_t size) { | 545 static int GetScaleFactor(intptr_t size) { |
| 559 switch (size) { | 546 switch (size) { |
| 560 case 1: return 0; | 547 case 1: return 0; |
| 561 case 2: return 1; | 548 case 2: return 1; |
| 562 case 4: return 2; | 549 case 4: return 2; |
| 563 case 8: return 3; | 550 case 8: return 3; |
| 564 case 16: return 4; | 551 case 16: return 4; |
| 565 } | 552 } |
| 566 UNREACHABLE(); | 553 UNREACHABLE(); |
| 567 return -1; | 554 return -1; |
| 568 }; | 555 }; |
| 569 | 556 |
| 570 | 557 |
| 571 #define TYPED_DATA_ALLOCATOR(clazz) \ | 558 #define TYPED_DATA_ALLOCATOR(clazz) \ |
| 572 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ | 559 void Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ |
| 573 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 560 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 574 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 561 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 575 int shift = GetScaleFactor(size); \ | 562 int shift = GetScaleFactor(size); \ |
| 576 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ | 563 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ |
| 577 return false; \ | |
| 578 } \ | 564 } \ |
| 579 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ | 565 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ |
| 580 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 566 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 581 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 567 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 582 int shift = GetScaleFactor(size); \ | 568 int shift = GetScaleFactor(size); \ |
| 583 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ | 569 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ |
| 584 return false; \ | |
| 585 } | 570 } |
| 586 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 571 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
| 587 #undef TYPED_DATA_ALLOCATOR | 572 #undef TYPED_DATA_ALLOCATOR |
| 588 | 573 |
| 589 | 574 |
| 590 // Loads args from stack into R0 and R1 | 575 // Loads args from stack into R0 and R1 |
| 591 // Tests if they are smis, jumps to label not_smi if not. | 576 // Tests if they are smis, jumps to label not_smi if not. |
| 592 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 577 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 593 __ ldr(R0, Address(SP, + 0 * kWordSize)); | 578 __ ldr(R0, Address(SP, + 0 * kWordSize)); |
| 594 __ ldr(R1, Address(SP, + 1 * kWordSize)); | 579 __ ldr(R1, Address(SP, + 1 * kWordSize)); |
| 595 __ orr(TMP, R0, ShifterOperand(R1)); | 580 __ orr(TMP, R0, ShifterOperand(R1)); |
| 596 __ tst(TMP, ShifterOperand(kSmiTagMask)); | 581 __ tst(TMP, ShifterOperand(kSmiTagMask)); |
| 597 __ b(not_smi, NE); | 582 __ b(not_smi, NE); |
| 598 return; | 583 return; |
| 599 } | 584 } |
| 600 | 585 |
| 601 | 586 |
| 602 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 587 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
| 603 Label fall_through; | 588 Label fall_through; |
| 604 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. | 589 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. |
| 605 __ adds(R0, R0, ShifterOperand(R1)); // Adds. | 590 __ adds(R0, R0, ShifterOperand(R1)); // Adds. |
| 606 __ bx(LR, VC); // Return if no overflow. | 591 __ bx(LR, VC); // Return if no overflow. |
| 607 // Otherwise fall through. | 592 // Otherwise fall through. |
| 608 __ Bind(&fall_through); | 593 __ Bind(&fall_through); |
| 609 return false; | |
| 610 } | 594 } |
| 611 | 595 |
| 612 | 596 |
| 613 bool Intrinsifier::Integer_add(Assembler* assembler) { | 597 void Intrinsifier::Integer_add(Assembler* assembler) { |
| 614 return Integer_addFromInteger(assembler); | 598 return Integer_addFromInteger(assembler); |
| 615 } | 599 } |
| 616 | 600 |
| 617 | 601 |
| 618 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 602 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
| 619 Label fall_through; | 603 Label fall_through; |
| 620 TestBothArgumentsSmis(assembler, &fall_through); | 604 TestBothArgumentsSmis(assembler, &fall_through); |
| 621 __ subs(R0, R0, ShifterOperand(R1)); // Subtract. | 605 __ subs(R0, R0, ShifterOperand(R1)); // Subtract. |
| 622 __ bx(LR, VC); // Return if no overflow. | 606 __ bx(LR, VC); // Return if no overflow. |
| 623 // Otherwise fall through. | 607 // Otherwise fall through. |
| 624 __ Bind(&fall_through); | 608 __ Bind(&fall_through); |
| 625 return false; | |
| 626 } | 609 } |
| 627 | 610 |
| 628 | 611 |
| 629 bool Intrinsifier::Integer_sub(Assembler* assembler) { | 612 void Intrinsifier::Integer_sub(Assembler* assembler) { |
| 630 Label fall_through; | 613 Label fall_through; |
| 631 TestBothArgumentsSmis(assembler, &fall_through); | 614 TestBothArgumentsSmis(assembler, &fall_through); |
| 632 __ subs(R0, R1, ShifterOperand(R0)); // Subtract. | 615 __ subs(R0, R1, ShifterOperand(R0)); // Subtract. |
| 633 __ bx(LR, VC); // Return if no overflow. | 616 __ bx(LR, VC); // Return if no overflow. |
| 634 // Otherwise fall through. | 617 // Otherwise fall through. |
| 635 __ Bind(&fall_through); | 618 __ Bind(&fall_through); |
| 636 return false; | |
| 637 } | 619 } |
| 638 | 620 |
| 639 | 621 |
| 640 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 622 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
| 641 Label fall_through; | 623 Label fall_through; |
| 642 | 624 |
| 643 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis | 625 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis |
| 644 __ SmiUntag(R0); // untags R6. only want result shifted by one | 626 __ SmiUntag(R0); // untags R6. only want result shifted by one |
| 645 | 627 |
| 646 __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1. | 628 __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1. |
| 647 __ cmp(IP, ShifterOperand(R0, ASR, 31)); | 629 __ cmp(IP, ShifterOperand(R0, ASR, 31)); |
| 648 __ bx(LR, EQ); | 630 __ bx(LR, EQ); |
| 649 __ Bind(&fall_through); // Fall through on overflow. | 631 __ Bind(&fall_through); // Fall through on overflow. |
| 650 return false; | |
| 651 } | 632 } |
| 652 | 633 |
| 653 | 634 |
| 654 bool Intrinsifier::Integer_mul(Assembler* assembler) { | 635 void Intrinsifier::Integer_mul(Assembler* assembler) { |
| 655 return Integer_mulFromInteger(assembler); | 636 return Integer_mulFromInteger(assembler); |
| 656 } | 637 } |
| 657 | 638 |
| 658 | 639 |
| 659 // Optimizations: | 640 // Optimizations: |
| 660 // - result is 0 if: | 641 // - result is 0 if: |
| 661 // - left is 0 | 642 // - left is 0 |
| 662 // - left equals right | 643 // - left equals right |
| 663 // - result is left if | 644 // - result is left if |
| 664 // - left > 0 && left < right | 645 // - left > 0 && left < right |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 | 686 |
| 706 // Implementation: | 687 // Implementation: |
| 707 // res = left % right; | 688 // res = left % right; |
| 708 // if (res < 0) { | 689 // if (res < 0) { |
| 709 // if (right < 0) { | 690 // if (right < 0) { |
| 710 // res = res - right; | 691 // res = res - right; |
| 711 // } else { | 692 // } else { |
| 712 // res = res + right; | 693 // res = res + right; |
| 713 // } | 694 // } |
| 714 // } | 695 // } |
| 715 bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 696 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
| 716 // Check to see if we have integer division | 697 // Check to see if we have integer division |
| 717 Label fall_through, subtract; | 698 Label fall_through, subtract; |
| 718 __ ldr(R1, Address(SP, + 0 * kWordSize)); | 699 __ ldr(R1, Address(SP, + 0 * kWordSize)); |
| 719 __ ldr(R0, Address(SP, + 1 * kWordSize)); | 700 __ ldr(R0, Address(SP, + 1 * kWordSize)); |
| 720 __ orr(TMP, R0, ShifterOperand(R1)); | 701 __ orr(TMP, R0, ShifterOperand(R1)); |
| 721 __ tst(TMP, ShifterOperand(kSmiTagMask)); | 702 __ tst(TMP, ShifterOperand(kSmiTagMask)); |
| 722 __ b(&fall_through, NE); | 703 __ b(&fall_through, NE); |
| 723 // R1: Tagged left (dividend). | 704 // R1: Tagged left (dividend). |
| 724 // R0: Tagged right (divisor). | 705 // R0: Tagged right (divisor). |
| 725 // Check if modulo by zero -> exception thrown in main function. | 706 // Check if modulo by zero -> exception thrown in main function. |
| 726 __ cmp(R0, ShifterOperand(0)); | 707 __ cmp(R0, ShifterOperand(0)); |
| 727 __ b(&fall_through, EQ); | 708 __ b(&fall_through, EQ); |
| 728 EmitRemainderOperation(assembler); | 709 EmitRemainderOperation(assembler); |
| 729 // Untagged right in R0. Untagged remainder result in R1. | 710 // Untagged right in R0. Untagged remainder result in R1. |
| 730 | 711 |
| 731 __ cmp(R1, ShifterOperand(0)); | 712 __ cmp(R1, ShifterOperand(0)); |
| 732 __ mov(R0, ShifterOperand(R1, LSL, 1), GE); // Tag and move result to R0. | 713 __ mov(R0, ShifterOperand(R1, LSL, 1), GE); // Tag and move result to R0. |
| 733 __ bx(LR, GE); | 714 __ bx(LR, GE); |
| 734 | 715 |
| 735 // Result is negative, adjust it. | 716 // Result is negative, adjust it. |
| 736 __ cmp(R0, ShifterOperand(0)); | 717 __ cmp(R0, ShifterOperand(0)); |
| 737 __ sub(R0, R1, ShifterOperand(R0), LT); | 718 __ sub(R0, R1, ShifterOperand(R0), LT); |
| 738 __ add(R0, R1, ShifterOperand(R0), GE); | 719 __ add(R0, R1, ShifterOperand(R0), GE); |
| 739 __ SmiTag(R0); | 720 __ SmiTag(R0); |
| 740 __ Ret(); | 721 __ Ret(); |
| 741 | 722 |
| 742 __ Bind(&fall_through); | 723 __ Bind(&fall_through); |
| 743 return false; | |
| 744 } | 724 } |
| 745 | 725 |
| 746 | 726 |
| 747 bool Intrinsifier::Integer_remainder(Assembler* assembler) { | 727 void Intrinsifier::Integer_remainder(Assembler* assembler) { |
| 748 // Check to see if we have integer division | 728 // Check to see if we have integer division |
| 749 Label fall_through; | 729 Label fall_through; |
| 750 TestBothArgumentsSmis(assembler, &fall_through); | 730 TestBothArgumentsSmis(assembler, &fall_through); |
| 751 // R1: Tagged left (dividend). | 731 // R1: Tagged left (dividend). |
| 752 // R0: Tagged right (divisor). | 732 // R0: Tagged right (divisor). |
| 753 // Check if modulo by zero -> exception thrown in main function. | 733 // Check if modulo by zero -> exception thrown in main function. |
| 754 __ cmp(R0, ShifterOperand(0)); | 734 __ cmp(R0, ShifterOperand(0)); |
| 755 __ b(&fall_through, EQ); | 735 __ b(&fall_through, EQ); |
| 756 EmitRemainderOperation(assembler); | 736 EmitRemainderOperation(assembler); |
| 757 // Untagged remainder result in R1. | 737 // Untagged remainder result in R1. |
| 758 __ mov(R0, ShifterOperand(R1, LSL, 1)); // Tag result and return. | 738 __ mov(R0, ShifterOperand(R1, LSL, 1)); // Tag result and return. |
| 759 __ Ret(); | 739 __ Ret(); |
| 760 | 740 |
| 761 __ Bind(&fall_through); | 741 __ Bind(&fall_through); |
| 762 return false; | |
| 763 } | 742 } |
| 764 | 743 |
| 765 | 744 |
| 766 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 745 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
| 767 // Check to see if we have integer division | 746 // Check to see if we have integer division |
| 768 Label fall_through; | 747 Label fall_through; |
| 769 | 748 |
| 770 TestBothArgumentsSmis(assembler, &fall_through); | 749 TestBothArgumentsSmis(assembler, &fall_through); |
| 771 __ cmp(R0, ShifterOperand(0)); | 750 __ cmp(R0, ShifterOperand(0)); |
| 772 __ b(&fall_through, EQ); // If b is 0, fall through. | 751 __ b(&fall_through, EQ); // If b is 0, fall through. |
| 773 | 752 |
| 774 __ SmiUntag(R0); | 753 __ SmiUntag(R0); |
| 775 __ SmiUntag(R1); | 754 __ SmiUntag(R1); |
| 776 | 755 |
| 777 __ IntegerDivide(R0, R1, R0, D1, D0); | 756 __ IntegerDivide(R0, R1, R0, D1, D0); |
| 778 | 757 |
| 779 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 758 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
| 780 // cannot tag the result. | 759 // cannot tag the result. |
| 781 __ CompareImmediate(R0, 0x40000000); | 760 __ CompareImmediate(R0, 0x40000000); |
| 782 __ SmiTag(R0, NE); // Not equal. Okay to tag and return. | 761 __ SmiTag(R0, NE); // Not equal. Okay to tag and return. |
| 783 __ bx(LR, NE); // Return. | 762 __ bx(LR, NE); // Return. |
| 784 __ Bind(&fall_through); | 763 __ Bind(&fall_through); |
| 785 return false; | |
| 786 } | 764 } |
| 787 | 765 |
| 788 | 766 |
| 789 bool Intrinsifier::Integer_negate(Assembler* assembler) { | 767 void Intrinsifier::Integer_negate(Assembler* assembler) { |
| 790 Label fall_through; | 768 Label fall_through; |
| 791 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument. | 769 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument. |
| 792 __ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi. | 770 __ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi. |
| 793 __ b(&fall_through, NE); | 771 __ b(&fall_through, NE); |
| 794 __ rsbs(R0, R0, ShifterOperand(0)); // R0 is a Smi. R0 <- 0 - R0. | 772 __ rsbs(R0, R0, ShifterOperand(0)); // R0 is a Smi. R0 <- 0 - R0. |
| 795 __ bx(LR, VC); // Return if there wasn't overflow, fall through otherwise. | 773 __ bx(LR, VC); // Return if there wasn't overflow, fall through otherwise. |
| 796 // R0 is not a Smi. Fall through. | 774 // R0 is not a Smi. Fall through. |
| 797 __ Bind(&fall_through); | 775 __ Bind(&fall_through); |
| 798 return false; | |
| 799 } | 776 } |
| 800 | 777 |
| 801 | 778 |
| 802 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 779 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
| 803 Label fall_through; | 780 Label fall_through; |
| 804 | 781 |
| 805 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis | 782 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis |
| 806 __ and_(R0, R0, ShifterOperand(R1)); | 783 __ and_(R0, R0, ShifterOperand(R1)); |
| 807 | 784 |
| 808 __ Ret(); | 785 __ Ret(); |
| 809 __ Bind(&fall_through); | 786 __ Bind(&fall_through); |
| 810 return false; | |
| 811 } | 787 } |
| 812 | 788 |
| 813 | 789 |
| 814 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { | 790 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
| 815 return Integer_bitAndFromInteger(assembler); | 791 return Integer_bitAndFromInteger(assembler); |
| 816 } | 792 } |
| 817 | 793 |
| 818 | 794 |
| 819 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { | 795 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
| 820 Label fall_through; | 796 Label fall_through; |
| 821 | 797 |
| 822 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis | 798 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis |
| 823 __ orr(R0, R0, ShifterOperand(R1)); | 799 __ orr(R0, R0, ShifterOperand(R1)); |
| 824 | 800 |
| 825 __ Ret(); | 801 __ Ret(); |
| 826 __ Bind(&fall_through); | 802 __ Bind(&fall_through); |
| 827 return false; | |
| 828 } | 803 } |
| 829 | 804 |
| 830 | 805 |
| 831 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { | 806 void Intrinsifier::Integer_bitOr(Assembler* assembler) { |
| 832 return Integer_bitOrFromInteger(assembler); | 807 return Integer_bitOrFromInteger(assembler); |
| 833 } | 808 } |
| 834 | 809 |
| 835 | 810 |
| 836 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 811 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
| 837 Label fall_through; | 812 Label fall_through; |
| 838 | 813 |
| 839 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis | 814 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis |
| 840 __ eor(R0, R0, ShifterOperand(R1)); | 815 __ eor(R0, R0, ShifterOperand(R1)); |
| 841 | 816 |
| 842 __ Ret(); | 817 __ Ret(); |
| 843 __ Bind(&fall_through); | 818 __ Bind(&fall_through); |
| 844 return false; | |
| 845 } | 819 } |
| 846 | 820 |
| 847 | 821 |
| 848 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { | 822 void Intrinsifier::Integer_bitXor(Assembler* assembler) { |
| 849 return Integer_bitXorFromInteger(assembler); | 823 return Integer_bitXorFromInteger(assembler); |
| 850 } | 824 } |
| 851 | 825 |
| 852 | 826 |
| 853 bool Intrinsifier::Integer_shl(Assembler* assembler) { | 827 void Intrinsifier::Integer_shl(Assembler* assembler) { |
| 854 ASSERT(kSmiTagShift == 1); | 828 ASSERT(kSmiTagShift == 1); |
| 855 ASSERT(kSmiTag == 0); | 829 ASSERT(kSmiTag == 0); |
| 856 Label fall_through; | 830 Label fall_through; |
| 857 | 831 |
| 858 TestBothArgumentsSmis(assembler, &fall_through); | 832 TestBothArgumentsSmis(assembler, &fall_through); |
| 859 __ CompareImmediate(R0, Smi::RawValue(Smi::kBits)); | 833 __ CompareImmediate(R0, Smi::RawValue(Smi::kBits)); |
| 860 __ b(&fall_through, HI); | 834 __ b(&fall_through, HI); |
| 861 | 835 |
| 862 __ SmiUntag(R0); | 836 __ SmiUntag(R0); |
| 863 | 837 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 891 | 865 |
| 892 const Class& mint_class = Class::Handle( | 866 const Class& mint_class = Class::Handle( |
| 893 Isolate::Current()->object_store()->mint_class()); | 867 Isolate::Current()->object_store()->mint_class()); |
| 894 __ TryAllocate(mint_class, &fall_through, R0); | 868 __ TryAllocate(mint_class, &fall_through, R0); |
| 895 | 869 |
| 896 | 870 |
| 897 __ str(R1, FieldAddress(R0, Mint::value_offset())); | 871 __ str(R1, FieldAddress(R0, Mint::value_offset())); |
| 898 __ str(R7, FieldAddress(R0, Mint::value_offset() + kWordSize)); | 872 __ str(R7, FieldAddress(R0, Mint::value_offset() + kWordSize)); |
| 899 __ Ret(); | 873 __ Ret(); |
| 900 __ Bind(&fall_through); | 874 __ Bind(&fall_through); |
| 901 return false; | |
| 902 } | 875 } |
| 903 | 876 |
| 904 | 877 |
| 905 static void Get64SmiOrMint(Assembler* assembler, | 878 static void Get64SmiOrMint(Assembler* assembler, |
| 906 Register res_hi, | 879 Register res_hi, |
| 907 Register res_lo, | 880 Register res_lo, |
| 908 Register reg, | 881 Register reg, |
| 909 Label* not_smi_or_mint) { | 882 Label* not_smi_or_mint) { |
| 910 Label not_smi, done; | 883 Label not_smi, done; |
| 911 __ tst(reg, ShifterOperand(kSmiTagMask)); | 884 __ tst(reg, ShifterOperand(kSmiTagMask)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 922 __ b(not_smi_or_mint, NE); | 895 __ b(not_smi_or_mint, NE); |
| 923 | 896 |
| 924 // Mint. | 897 // Mint. |
| 925 __ ldr(res_lo, FieldAddress(reg, Mint::value_offset())); | 898 __ ldr(res_lo, FieldAddress(reg, Mint::value_offset())); |
| 926 __ ldr(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize)); | 899 __ ldr(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize)); |
| 927 __ Bind(&done); | 900 __ Bind(&done); |
| 928 return; | 901 return; |
| 929 } | 902 } |
| 930 | 903 |
| 931 | 904 |
| 932 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { | 905 static void CompareIntegers(Assembler* assembler, Condition true_condition) { |
| 933 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; | 906 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; |
| 934 TestBothArgumentsSmis(assembler, &try_mint_smi); | 907 TestBothArgumentsSmis(assembler, &try_mint_smi); |
| 935 // R0 contains the right argument. R1 contains left argument | 908 // R0 contains the right argument. R1 contains left argument |
| 936 | 909 |
| 937 __ cmp(R1, ShifterOperand(R0)); | 910 __ cmp(R1, ShifterOperand(R0)); |
| 938 __ b(&is_true, true_condition); | 911 __ b(&is_true, true_condition); |
| 939 __ Bind(&is_false); | 912 __ Bind(&is_false); |
| 940 __ LoadObject(R0, Bool::False()); | 913 __ LoadObject(R0, Bool::False()); |
| 941 __ Ret(); | 914 __ Ret(); |
| 942 __ Bind(&is_true); | 915 __ Bind(&is_true); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 975 | 948 |
| 976 __ cmp(R3, ShifterOperand(R7)); // Compare left hi, right high. | 949 __ cmp(R3, ShifterOperand(R7)); // Compare left hi, right high. |
| 977 __ b(&is_false, hi_false_cond); | 950 __ b(&is_false, hi_false_cond); |
| 978 __ b(&is_true, hi_true_cond); | 951 __ b(&is_true, hi_true_cond); |
| 979 __ cmp(R2, ShifterOperand(R6)); // Compare left lo, right lo. | 952 __ cmp(R2, ShifterOperand(R6)); // Compare left lo, right lo. |
| 980 __ b(&is_false, lo_false_cond); | 953 __ b(&is_false, lo_false_cond); |
| 981 // Else is true. | 954 // Else is true. |
| 982 __ b(&is_true); | 955 __ b(&is_true); |
| 983 | 956 |
| 984 __ Bind(&fall_through); | 957 __ Bind(&fall_through); |
| 985 return false; | |
| 986 } | 958 } |
| 987 | 959 |
| 988 | 960 |
| 989 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { | 961 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { |
| 990 return CompareIntegers(assembler, LT); | 962 return CompareIntegers(assembler, LT); |
| 991 } | 963 } |
| 992 | 964 |
| 993 | 965 |
| 994 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { | 966 void Intrinsifier::Integer_lessThan(Assembler* assembler) { |
| 995 return Integer_greaterThanFromInt(assembler); | 967 return Integer_greaterThanFromInt(assembler); |
| 996 } | 968 } |
| 997 | 969 |
| 998 | 970 |
| 999 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { | 971 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { |
| 1000 return CompareIntegers(assembler, GT); | 972 return CompareIntegers(assembler, GT); |
| 1001 } | 973 } |
| 1002 | 974 |
| 1003 | 975 |
| 1004 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { | 976 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { |
| 1005 return CompareIntegers(assembler, LE); | 977 return CompareIntegers(assembler, LE); |
| 1006 } | 978 } |
| 1007 | 979 |
| 1008 | 980 |
| 1009 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { | 981 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { |
| 1010 return CompareIntegers(assembler, GE); | 982 return CompareIntegers(assembler, GE); |
| 1011 } | 983 } |
| 1012 | 984 |
| 1013 | 985 |
| 1014 // This is called for Smi, Mint and Bigint receivers. The right argument | 986 // This is called for Smi, Mint and Bigint receivers. The right argument |
| 1015 // can be Smi, Mint, Bigint or double. | 987 // can be Smi, Mint, Bigint or double. |
| 1016 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 988 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
| 1017 Label fall_through, true_label, check_for_mint; | 989 Label fall_through, true_label, check_for_mint; |
| 1018 // For integer receiver '===' check first. | 990 // For integer receiver '===' check first. |
| 1019 __ ldr(R0, Address(SP, 0 * kWordSize)); | 991 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1020 __ ldr(R1, Address(SP, 1 * kWordSize)); | 992 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| 1021 __ cmp(R0, ShifterOperand(R1)); | 993 __ cmp(R0, ShifterOperand(R1)); |
| 1022 __ b(&true_label, EQ); | 994 __ b(&true_label, EQ); |
| 1023 | 995 |
| 1024 __ orr(R2, R0, ShifterOperand(R1)); | 996 __ orr(R2, R0, ShifterOperand(R1)); |
| 1025 __ tst(R2, ShifterOperand(kSmiTagMask)); | 997 __ tst(R2, ShifterOperand(kSmiTagMask)); |
| 1026 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks. | 998 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1054 __ CompareClassId(R1, kMintCid, R2); | 1026 __ CompareClassId(R1, kMintCid, R2); |
| 1055 __ b(&fall_through, NE); | 1027 __ b(&fall_through, NE); |
| 1056 // Receiver is Mint, return false if right is Smi. | 1028 // Receiver is Mint, return false if right is Smi. |
| 1057 __ tst(R0, ShifterOperand(kSmiTagMask)); | 1029 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 1058 __ b(&fall_through, NE); | 1030 __ b(&fall_through, NE); |
| 1059 __ LoadObject(R0, Bool::False()); | 1031 __ LoadObject(R0, Bool::False()); |
| 1060 __ Ret(); | 1032 __ Ret(); |
| 1061 // TODO(srdjan): Implement Mint == Mint comparison. | 1033 // TODO(srdjan): Implement Mint == Mint comparison. |
| 1062 | 1034 |
| 1063 __ Bind(&fall_through); | 1035 __ Bind(&fall_through); |
| 1064 return false; | |
| 1065 } | 1036 } |
| 1066 | 1037 |
| 1067 | 1038 |
| 1068 bool Intrinsifier::Integer_equal(Assembler* assembler) { | 1039 void Intrinsifier::Integer_equal(Assembler* assembler) { |
| 1069 return Integer_equalToInteger(assembler); | 1040 return Integer_equalToInteger(assembler); |
| 1070 } | 1041 } |
| 1071 | 1042 |
| 1072 | 1043 |
| 1073 bool Intrinsifier::Integer_sar(Assembler* assembler) { | 1044 void Intrinsifier::Integer_sar(Assembler* assembler) { |
| 1074 Label fall_through; | 1045 Label fall_through; |
| 1075 | 1046 |
| 1076 TestBothArgumentsSmis(assembler, &fall_through); | 1047 TestBothArgumentsSmis(assembler, &fall_through); |
| 1077 // Shift amount in R0. Value to shift in R1. | 1048 // Shift amount in R0. Value to shift in R1. |
| 1078 | 1049 |
| 1079 // Fall through if shift amount is negative. | 1050 // Fall through if shift amount is negative. |
| 1080 __ SmiUntag(R0); | 1051 __ SmiUntag(R0); |
| 1081 __ CompareImmediate(R0, 0); | 1052 __ CompareImmediate(R0, 0); |
| 1082 __ b(&fall_through, LT); | 1053 __ b(&fall_through, LT); |
| 1083 | 1054 |
| 1084 // If shift amount is bigger than 31, set to 31. | 1055 // If shift amount is bigger than 31, set to 31. |
| 1085 __ CompareImmediate(R0, 0x1F); | 1056 __ CompareImmediate(R0, 0x1F); |
| 1086 __ LoadImmediate(R0, 0x1F, GT); | 1057 __ LoadImmediate(R0, 0x1F, GT); |
| 1087 __ SmiUntag(R1); | 1058 __ SmiUntag(R1); |
| 1088 __ mov(R0, ShifterOperand(R1, ASR, R0)); | 1059 __ mov(R0, ShifterOperand(R1, ASR, R0)); |
| 1089 __ SmiTag(R0); | 1060 __ SmiTag(R0); |
| 1090 __ Ret(); | 1061 __ Ret(); |
| 1091 __ Bind(&fall_through); | 1062 __ Bind(&fall_through); |
| 1092 return false; | |
| 1093 } | 1063 } |
| 1094 | 1064 |
| 1095 | 1065 |
| 1096 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 1066 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
| 1097 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1067 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1098 __ mvn(R0, ShifterOperand(R0)); | 1068 __ mvn(R0, ShifterOperand(R0)); |
| 1099 __ bic(R0, R0, ShifterOperand(kSmiTagMask)); // Remove inverted smi-tag. | 1069 __ bic(R0, R0, ShifterOperand(kSmiTagMask)); // Remove inverted smi-tag. |
| 1100 __ Ret(); | 1070 __ Ret(); |
| 1101 return true; | |
| 1102 } | 1071 } |
| 1103 | 1072 |
| 1104 | 1073 |
| 1105 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1074 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 1106 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1075 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 1107 // Returns the last argument in R0. | 1076 // Returns the last argument in R0. |
| 1108 static void TestLastArgumentIsDouble(Assembler* assembler, | 1077 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 1109 Label* is_smi, | 1078 Label* is_smi, |
| 1110 Label* not_double_smi) { | 1079 Label* not_double_smi) { |
| 1111 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1080 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1112 __ tst(R0, ShifterOperand(kSmiTagMask)); | 1081 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 1113 __ b(is_smi, EQ); | 1082 __ b(is_smi, EQ); |
| 1114 __ CompareClassId(R0, kDoubleCid, R1); | 1083 __ CompareClassId(R0, kDoubleCid, R1); |
| 1115 __ b(not_double_smi, NE); | 1084 __ b(not_double_smi, NE); |
| 1116 // Fall through with Double in R0. | 1085 // Fall through with Double in R0. |
| 1117 } | 1086 } |
| 1118 | 1087 |
| 1119 | 1088 |
| 1120 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 1089 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
| 1121 // type. Return true or false object in the register R0. Any NaN argument | 1090 // type. Return true or false object in the register R0. Any NaN argument |
| 1122 // returns false. Any non-double arg1 causes control flow to fall through to the | 1091 // returns false. Any non-double arg1 causes control flow to fall through to the |
| 1123 // slow case (compiled method body). | 1092 // slow case (compiled method body). |
| 1124 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { | 1093 static void CompareDoubles(Assembler* assembler, Condition true_condition) { |
| 1125 Label fall_through, is_smi, double_op; | 1094 Label fall_through, is_smi, double_op; |
| 1126 | 1095 |
| 1127 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1096 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1128 // Both arguments are double, right operand is in R0. | 1097 // Both arguments are double, right operand is in R0. |
| 1129 | 1098 |
| 1130 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); | 1099 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); |
| 1131 __ Bind(&double_op); | 1100 __ Bind(&double_op); |
| 1132 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. | 1101 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. |
| 1133 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1102 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1134 | 1103 |
| 1135 __ vcmpd(D0, D1); | 1104 __ vcmpd(D0, D1); |
| 1136 __ vmstat(); | 1105 __ vmstat(); |
| 1137 __ LoadObject(R0, Bool::False()); | 1106 __ LoadObject(R0, Bool::False()); |
| 1138 // Return false if D0 or D1 was NaN before checking true condition. | 1107 // Return false if D0 or D1 was NaN before checking true condition. |
| 1139 __ bx(LR, VS); | 1108 __ bx(LR, VS); |
| 1140 __ LoadObject(R0, Bool::True(), true_condition); | 1109 __ LoadObject(R0, Bool::True(), true_condition); |
| 1141 __ Ret(); | 1110 __ Ret(); |
| 1142 | 1111 |
| 1143 __ Bind(&is_smi); // Convert R0 to a double. | 1112 __ Bind(&is_smi); // Convert R0 to a double. |
| 1144 __ SmiUntag(R0); | 1113 __ SmiUntag(R0); |
| 1145 __ vmovsr(S0, R0); | 1114 __ vmovsr(S0, R0); |
| 1146 __ vcvtdi(D1, S0); | 1115 __ vcvtdi(D1, S0); |
| 1147 __ b(&double_op); // Then do the comparison. | 1116 __ b(&double_op); // Then do the comparison. |
| 1148 __ Bind(&fall_through); | 1117 __ Bind(&fall_through); |
| 1149 return false; | |
| 1150 } | 1118 } |
| 1151 | 1119 |
| 1152 | 1120 |
| 1153 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { | 1121 void Intrinsifier::Double_greaterThan(Assembler* assembler) { |
| 1154 return CompareDoubles(assembler, HI); | 1122 return CompareDoubles(assembler, HI); |
| 1155 } | 1123 } |
| 1156 | 1124 |
| 1157 | 1125 |
| 1158 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { | 1126 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { |
| 1159 return CompareDoubles(assembler, CS); | 1127 return CompareDoubles(assembler, CS); |
| 1160 } | 1128 } |
| 1161 | 1129 |
| 1162 | 1130 |
| 1163 bool Intrinsifier::Double_lessThan(Assembler* assembler) { | 1131 void Intrinsifier::Double_lessThan(Assembler* assembler) { |
| 1164 return CompareDoubles(assembler, CC); | 1132 return CompareDoubles(assembler, CC); |
| 1165 } | 1133 } |
| 1166 | 1134 |
| 1167 | 1135 |
| 1168 bool Intrinsifier::Double_equal(Assembler* assembler) { | 1136 void Intrinsifier::Double_equal(Assembler* assembler) { |
| 1169 return CompareDoubles(assembler, EQ); | 1137 return CompareDoubles(assembler, EQ); |
| 1170 } | 1138 } |
| 1171 | 1139 |
| 1172 | 1140 |
| 1173 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { | 1141 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { |
| 1174 return CompareDoubles(assembler, LS); | 1142 return CompareDoubles(assembler, LS); |
| 1175 } | 1143 } |
| 1176 | 1144 |
| 1177 | 1145 |
| 1178 // Expects left argument to be double (receiver). Right argument is unknown. | 1146 // Expects left argument to be double (receiver). Right argument is unknown. |
| 1179 // Both arguments are on stack. | 1147 // Both arguments are on stack. |
| 1180 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 1148 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
| 1181 Label fall_through; | 1149 Label fall_through; |
| 1182 | 1150 |
| 1183 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); | 1151 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); |
| 1184 // Both arguments are double, right operand is in R0. | 1152 // Both arguments are double, right operand is in R0. |
| 1185 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); | 1153 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); |
| 1186 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. | 1154 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. |
| 1187 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1155 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1188 switch (kind) { | 1156 switch (kind) { |
| 1189 case Token::kADD: __ vaddd(D0, D0, D1); break; | 1157 case Token::kADD: __ vaddd(D0, D0, D1); break; |
| 1190 case Token::kSUB: __ vsubd(D0, D0, D1); break; | 1158 case Token::kSUB: __ vsubd(D0, D0, D1); break; |
| 1191 case Token::kMUL: __ vmuld(D0, D0, D1); break; | 1159 case Token::kMUL: __ vmuld(D0, D0, D1); break; |
| 1192 case Token::kDIV: __ vdivd(D0, D0, D1); break; | 1160 case Token::kDIV: __ vdivd(D0, D0, D1); break; |
| 1193 default: UNREACHABLE(); | 1161 default: UNREACHABLE(); |
| 1194 } | 1162 } |
| 1195 const Class& double_class = Class::Handle( | 1163 const Class& double_class = Class::Handle( |
| 1196 Isolate::Current()->object_store()->double_class()); | 1164 Isolate::Current()->object_store()->double_class()); |
| 1197 __ TryAllocate(double_class, &fall_through, R0); // Result register. | 1165 __ TryAllocate(double_class, &fall_through, R0); // Result register. |
| 1198 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1166 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1199 __ Ret(); | 1167 __ Ret(); |
| 1200 __ Bind(&fall_through); | 1168 __ Bind(&fall_through); |
| 1201 return false; | |
| 1202 } | 1169 } |
| 1203 | 1170 |
| 1204 | 1171 |
| 1205 bool Intrinsifier::Double_add(Assembler* assembler) { | 1172 void Intrinsifier::Double_add(Assembler* assembler) { |
| 1206 return DoubleArithmeticOperations(assembler, Token::kADD); | 1173 return DoubleArithmeticOperations(assembler, Token::kADD); |
| 1207 } | 1174 } |
| 1208 | 1175 |
| 1209 | 1176 |
| 1210 bool Intrinsifier::Double_mul(Assembler* assembler) { | 1177 void Intrinsifier::Double_mul(Assembler* assembler) { |
| 1211 return DoubleArithmeticOperations(assembler, Token::kMUL); | 1178 return DoubleArithmeticOperations(assembler, Token::kMUL); |
| 1212 } | 1179 } |
| 1213 | 1180 |
| 1214 | 1181 |
| 1215 bool Intrinsifier::Double_sub(Assembler* assembler) { | 1182 void Intrinsifier::Double_sub(Assembler* assembler) { |
| 1216 return DoubleArithmeticOperations(assembler, Token::kSUB); | 1183 return DoubleArithmeticOperations(assembler, Token::kSUB); |
| 1217 } | 1184 } |
| 1218 | 1185 |
| 1219 | 1186 |
| 1220 bool Intrinsifier::Double_div(Assembler* assembler) { | 1187 void Intrinsifier::Double_div(Assembler* assembler) { |
| 1221 return DoubleArithmeticOperations(assembler, Token::kDIV); | 1188 return DoubleArithmeticOperations(assembler, Token::kDIV); |
| 1222 } | 1189 } |
| 1223 | 1190 |
| 1224 | 1191 |
| 1225 // Left is double right is integer (Bigint, Mint or Smi) | 1192 // Left is double right is integer (Bigint, Mint or Smi) |
| 1226 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 1193 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 1227 Label fall_through; | 1194 Label fall_through; |
| 1228 // Only Smi-s allowed. | 1195 // Only Smi-s allowed. |
| 1229 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1196 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1230 __ tst(R0, ShifterOperand(kSmiTagMask)); | 1197 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 1231 __ b(&fall_through, NE); | 1198 __ b(&fall_through, NE); |
| 1232 // Is Smi. | 1199 // Is Smi. |
| 1233 __ SmiUntag(R0); | 1200 __ SmiUntag(R0); |
| 1234 __ vmovsr(S0, R0); | 1201 __ vmovsr(S0, R0); |
| 1235 __ vcvtdi(D1, S0); | 1202 __ vcvtdi(D1, S0); |
| 1236 __ ldr(R0, Address(SP, 1 * kWordSize)); | 1203 __ ldr(R0, Address(SP, 1 * kWordSize)); |
| 1237 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1204 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1238 __ vmuld(D0, D0, D1); | 1205 __ vmuld(D0, D0, D1); |
| 1239 const Class& double_class = Class::Handle( | 1206 const Class& double_class = Class::Handle( |
| 1240 Isolate::Current()->object_store()->double_class()); | 1207 Isolate::Current()->object_store()->double_class()); |
| 1241 __ TryAllocate(double_class, &fall_through, R0); // Result register. | 1208 __ TryAllocate(double_class, &fall_through, R0); // Result register. |
| 1242 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1209 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1243 __ Ret(); | 1210 __ Ret(); |
| 1244 __ Bind(&fall_through); | 1211 __ Bind(&fall_through); |
| 1245 return false; | |
| 1246 } | 1212 } |
| 1247 | 1213 |
| 1248 | 1214 |
| 1249 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { | 1215 void Intrinsifier::Double_fromInteger(Assembler* assembler) { |
| 1250 Label fall_through; | 1216 Label fall_through; |
| 1251 | 1217 |
| 1252 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1218 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1253 __ tst(R0, ShifterOperand(kSmiTagMask)); | 1219 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 1254 __ b(&fall_through, NE); | 1220 __ b(&fall_through, NE); |
| 1255 // Is Smi. | 1221 // Is Smi. |
| 1256 __ SmiUntag(R0); | 1222 __ SmiUntag(R0); |
| 1257 __ vmovsr(S0, R0); | 1223 __ vmovsr(S0, R0); |
| 1258 __ vcvtdi(D0, S0); | 1224 __ vcvtdi(D0, S0); |
| 1259 const Class& double_class = Class::Handle( | 1225 const Class& double_class = Class::Handle( |
| 1260 Isolate::Current()->object_store()->double_class()); | 1226 Isolate::Current()->object_store()->double_class()); |
| 1261 __ TryAllocate(double_class, &fall_through, R0); // Result register. | 1227 __ TryAllocate(double_class, &fall_through, R0); // Result register. |
| 1262 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1228 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1263 __ Ret(); | 1229 __ Ret(); |
| 1264 __ Bind(&fall_through); | 1230 __ Bind(&fall_through); |
| 1265 return false; | |
| 1266 } | 1231 } |
| 1267 | 1232 |
| 1268 | 1233 |
| 1269 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1234 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
| 1270 Label is_true; | 1235 Label is_true; |
| 1271 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1236 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1272 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1237 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1273 __ vcmpd(D0, D0); | 1238 __ vcmpd(D0, D0); |
| 1274 __ vmstat(); | 1239 __ vmstat(); |
| 1275 __ LoadObject(R0, Bool::False(), VC); | 1240 __ LoadObject(R0, Bool::False(), VC); |
| 1276 __ LoadObject(R0, Bool::True(), VS); | 1241 __ LoadObject(R0, Bool::True(), VS); |
| 1277 __ Ret(); | 1242 __ Ret(); |
| 1278 return true; | |
| 1279 } | 1243 } |
| 1280 | 1244 |
| 1281 | 1245 |
| 1282 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1246 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
| 1283 Label is_false, is_true, is_zero; | 1247 Label is_false, is_true, is_zero; |
| 1284 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1248 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1285 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1249 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1286 __ LoadDImmediate(D1, 0.0, R1); | 1250 __ LoadDImmediate(D1, 0.0, R1); |
| 1287 __ vcmpd(D0, D1); | 1251 __ vcmpd(D0, D1); |
| 1288 __ vmstat(); | 1252 __ vmstat(); |
| 1289 __ b(&is_false, VS); // NaN -> false. | 1253 __ b(&is_false, VS); // NaN -> false. |
| 1290 __ b(&is_zero, EQ); // Check for negative zero. | 1254 __ b(&is_zero, EQ); // Check for negative zero. |
| 1291 __ b(&is_false, CS); // >= 0 -> false. | 1255 __ b(&is_false, CS); // >= 0 -> false. |
| 1292 | 1256 |
| 1293 __ Bind(&is_true); | 1257 __ Bind(&is_true); |
| 1294 __ LoadObject(R0, Bool::True()); | 1258 __ LoadObject(R0, Bool::True()); |
| 1295 __ Ret(); | 1259 __ Ret(); |
| 1296 | 1260 |
| 1297 __ Bind(&is_false); | 1261 __ Bind(&is_false); |
| 1298 __ LoadObject(R0, Bool::False()); | 1262 __ LoadObject(R0, Bool::False()); |
| 1299 __ Ret(); | 1263 __ Ret(); |
| 1300 | 1264 |
| 1301 __ Bind(&is_zero); | 1265 __ Bind(&is_zero); |
| 1302 // Check for negative zero by looking at the sign bit. | 1266 // Check for negative zero by looking at the sign bit. |
| 1303 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1. | 1267 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1. |
| 1304 __ mov(R1, ShifterOperand(R1, LSR, 31)); | 1268 __ mov(R1, ShifterOperand(R1, LSR, 31)); |
| 1305 __ tst(R1, ShifterOperand(1)); | 1269 __ tst(R1, ShifterOperand(1)); |
| 1306 __ b(&is_true, NE); // Sign bit set. | 1270 __ b(&is_true, NE); // Sign bit set. |
| 1307 __ b(&is_false); | 1271 __ b(&is_false); |
| 1308 return true; | |
| 1309 } | 1272 } |
| 1310 | 1273 |
| 1311 | 1274 |
| 1312 bool Intrinsifier::Double_toInt(Assembler* assembler) { | 1275 void Intrinsifier::Double_toInt(Assembler* assembler) { |
| 1313 Label fall_through; | 1276 Label fall_through; |
| 1314 | 1277 |
| 1315 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1278 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1316 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1279 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1317 | 1280 |
| 1318 // Explicit NaN check, since ARM gives an FPU exception if you try to | 1281 // Explicit NaN check, since ARM gives an FPU exception if you try to |
| 1319 // convert NaN to an int. | 1282 // convert NaN to an int. |
| 1320 __ vcmpd(D0, D0); | 1283 __ vcmpd(D0, D0); |
| 1321 __ vmstat(); | 1284 __ vmstat(); |
| 1322 __ b(&fall_through, VS); | 1285 __ b(&fall_through, VS); |
| 1323 | 1286 |
| 1324 __ vcvtid(S0, D0); | 1287 __ vcvtid(S0, D0); |
| 1325 __ vmovrs(R0, S0); | 1288 __ vmovrs(R0, S0); |
| 1326 // Overflow is signaled with minint. | 1289 // Overflow is signaled with minint. |
| 1327 // Check for overflow and that it fits into Smi. | 1290 // Check for overflow and that it fits into Smi. |
| 1328 __ CompareImmediate(R0, 0xC0000000); | 1291 __ CompareImmediate(R0, 0xC0000000); |
| 1329 __ b(&fall_through, MI); | 1292 __ b(&fall_through, MI); |
| 1330 __ SmiTag(R0); | 1293 __ SmiTag(R0); |
| 1331 __ Ret(); | 1294 __ Ret(); |
| 1332 __ Bind(&fall_through); | 1295 __ Bind(&fall_through); |
| 1333 return false; | |
| 1334 } | 1296 } |
| 1335 | 1297 |
| 1336 | 1298 |
| 1337 bool Intrinsifier::Math_sqrt(Assembler* assembler) { | 1299 void Intrinsifier::Math_sqrt(Assembler* assembler) { |
| 1338 Label fall_through, is_smi, double_op; | 1300 Label fall_through, is_smi, double_op; |
| 1339 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1301 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1340 // Argument is double and is in R0. | 1302 // Argument is double and is in R0. |
| 1341 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); | 1303 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); |
| 1342 __ Bind(&double_op); | 1304 __ Bind(&double_op); |
| 1343 __ vsqrtd(D0, D1); | 1305 __ vsqrtd(D0, D1); |
| 1344 const Class& double_class = Class::Handle( | 1306 const Class& double_class = Class::Handle( |
| 1345 Isolate::Current()->object_store()->double_class()); | 1307 Isolate::Current()->object_store()->double_class()); |
| 1346 __ TryAllocate(double_class, &fall_through, R0); // Result register. | 1308 __ TryAllocate(double_class, &fall_through, R0); // Result register. |
| 1347 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); | 1309 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); |
| 1348 __ Ret(); | 1310 __ Ret(); |
| 1349 __ Bind(&is_smi); | 1311 __ Bind(&is_smi); |
| 1350 __ SmiUntag(R0); | 1312 __ SmiUntag(R0); |
| 1351 __ vmovsr(S0, R0); | 1313 __ vmovsr(S0, R0); |
| 1352 __ vcvtdi(D1, S0); | 1314 __ vcvtdi(D1, S0); |
| 1353 __ b(&double_op); | 1315 __ b(&double_op); |
| 1354 __ Bind(&fall_through); | 1316 __ Bind(&fall_through); |
| 1355 return false; | |
| 1356 } | 1317 } |
| 1357 | 1318 |
| 1358 | 1319 |
| 1359 bool Intrinsifier::Math_sin(Assembler* assembler) { | 1320 void Intrinsifier::Math_sin(Assembler* assembler) { |
| 1360 return false; | |
| 1361 } | 1321 } |
| 1362 | 1322 |
| 1363 | 1323 |
| 1364 bool Intrinsifier::Math_cos(Assembler* assembler) { | 1324 void Intrinsifier::Math_cos(Assembler* assembler) { |
| 1365 return false; | |
| 1366 } | 1325 } |
| 1367 | 1326 |
| 1368 | 1327 |
| 1369 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; | 1328 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
| 1370 // _state[kSTATE_LO] = state & _MASK_32; | 1329 // _state[kSTATE_LO] = state & _MASK_32; |
| 1371 // _state[kSTATE_HI] = state >> 32; | 1330 // _state[kSTATE_HI] = state >> 32; |
| 1372 bool Intrinsifier::Random_nextState(Assembler* assembler) { | 1331 void Intrinsifier::Random_nextState(Assembler* assembler) { |
| 1373 const Library& math_lib = Library::Handle(Library::MathLibrary()); | 1332 const Library& math_lib = Library::Handle(Library::MathLibrary()); |
| 1374 ASSERT(!math_lib.IsNull()); | 1333 ASSERT(!math_lib.IsNull()); |
| 1375 const Class& random_class = Class::Handle( | 1334 const Class& random_class = Class::Handle( |
| 1376 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); | 1335 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); |
| 1377 ASSERT(!random_class.IsNull()); | 1336 ASSERT(!random_class.IsNull()); |
| 1378 const Field& state_field = Field::ZoneHandle( | 1337 const Field& state_field = Field::ZoneHandle( |
| 1379 random_class.LookupInstanceField(Symbols::_state())); | 1338 random_class.LookupInstanceField(Symbols::_state())); |
| 1380 ASSERT(!state_field.IsNull()); | 1339 ASSERT(!state_field.IsNull()); |
| 1381 const Field& random_A_field = Field::ZoneHandle( | 1340 const Field& random_A_field = Field::ZoneHandle( |
| 1382 random_class.LookupStaticField(Symbols::_A())); | 1341 random_class.LookupStaticField(Symbols::_A())); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1401 | 1360 |
| 1402 __ LoadImmediate(R0, a_int32_value); | 1361 __ LoadImmediate(R0, a_int32_value); |
| 1403 __ LoadFromOffset(kWord, R2, R1, disp_0 - kHeapObjectTag); | 1362 __ LoadFromOffset(kWord, R2, R1, disp_0 - kHeapObjectTag); |
| 1404 __ LoadFromOffset(kWord, R3, R1, disp_1 - kHeapObjectTag); | 1363 __ LoadFromOffset(kWord, R3, R1, disp_1 - kHeapObjectTag); |
| 1405 __ mov(R6, ShifterOperand(0)); // Zero extend unsigned _state[kSTATE_HI]. | 1364 __ mov(R6, ShifterOperand(0)); // Zero extend unsigned _state[kSTATE_HI]. |
| 1406 // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3. | 1365 // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3. |
| 1407 __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2. | 1366 __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2. |
| 1408 __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag); | 1367 __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag); |
| 1409 __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag); | 1368 __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag); |
| 1410 __ Ret(); | 1369 __ Ret(); |
| 1411 return true; | |
| 1412 } | 1370 } |
| 1413 | 1371 |
| 1414 | 1372 |
| 1415 bool Intrinsifier::Object_equal(Assembler* assembler) { | 1373 void Intrinsifier::Object_equal(Assembler* assembler) { |
| 1416 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1374 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1417 __ ldr(R1, Address(SP, 1 * kWordSize)); | 1375 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| 1418 __ cmp(R0, ShifterOperand(R1)); | 1376 __ cmp(R0, ShifterOperand(R1)); |
| 1419 __ LoadObject(R0, Bool::False(), NE); | 1377 __ LoadObject(R0, Bool::False(), NE); |
| 1420 __ LoadObject(R0, Bool::True(), EQ); | 1378 __ LoadObject(R0, Bool::True(), EQ); |
| 1421 __ Ret(); | 1379 __ Ret(); |
| 1422 return true; | |
| 1423 } | 1380 } |
| 1424 | 1381 |
| 1425 | 1382 |
| 1426 bool Intrinsifier::String_getHashCode(Assembler* assembler) { | 1383 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1427 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1384 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1428 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | 1385 __ ldr(R0, FieldAddress(R0, String::hash_offset())); |
| 1429 __ cmp(R0, ShifterOperand(0)); | 1386 __ cmp(R0, ShifterOperand(0)); |
| 1430 __ bx(LR, NE); // Hash not yet computed. | 1387 __ bx(LR, NE); // Hash not yet computed. |
| 1431 return false; | |
| 1432 } | 1388 } |
| 1433 | 1389 |
| 1434 | 1390 |
| 1435 bool Intrinsifier::String_getLength(Assembler* assembler) { | 1391 void Intrinsifier::String_getLength(Assembler* assembler) { |
| 1436 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1392 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1437 __ ldr(R0, FieldAddress(R0, String::length_offset())); | 1393 __ ldr(R0, FieldAddress(R0, String::length_offset())); |
| 1438 __ Ret(); | 1394 __ Ret(); |
| 1439 return true; | |
| 1440 } | 1395 } |
| 1441 | 1396 |
| 1442 | 1397 |
| 1443 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1398 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { |
| 1444 Label fall_through, try_two_byte_string; | 1399 Label fall_through, try_two_byte_string; |
| 1445 | 1400 |
| 1446 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1401 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1447 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1402 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1448 __ tst(R1, ShifterOperand(kSmiTagMask)); | 1403 __ tst(R1, ShifterOperand(kSmiTagMask)); |
| 1449 __ b(&fall_through, NE); // Index is not a Smi. | 1404 __ b(&fall_through, NE); // Index is not a Smi. |
| 1450 // Range check. | 1405 // Range check. |
| 1451 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1406 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1452 __ cmp(R1, ShifterOperand(R2)); | 1407 __ cmp(R1, ShifterOperand(R2)); |
| 1453 __ b(&fall_through, CS); // Runtime throws exception. | 1408 __ b(&fall_through, CS); // Runtime throws exception. |
| 1454 __ CompareClassId(R0, kOneByteStringCid, R3); | 1409 __ CompareClassId(R0, kOneByteStringCid, R3); |
| 1455 __ b(&try_two_byte_string, NE); | 1410 __ b(&try_two_byte_string, NE); |
| 1456 __ SmiUntag(R1); | 1411 __ SmiUntag(R1); |
| 1457 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); | 1412 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); |
| 1458 __ ldrb(R0, Address(R0, R1)); | 1413 __ ldrb(R0, Address(R0, R1)); |
| 1459 __ SmiTag(R0); | 1414 __ SmiTag(R0); |
| 1460 __ Ret(); | 1415 __ Ret(); |
| 1461 | 1416 |
| 1462 __ Bind(&try_two_byte_string); | 1417 __ Bind(&try_two_byte_string); |
| 1463 __ CompareClassId(R0, kTwoByteStringCid, R3); | 1418 __ CompareClassId(R0, kTwoByteStringCid, R3); |
| 1464 __ b(&fall_through, NE); | 1419 __ b(&fall_through, NE); |
| 1465 ASSERT(kSmiTagShift == 1); | 1420 ASSERT(kSmiTagShift == 1); |
| 1466 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); | 1421 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); |
| 1467 __ ldrh(R0, Address(R0, R1)); | 1422 __ ldrh(R0, Address(R0, R1)); |
| 1468 __ SmiTag(R0); | 1423 __ SmiTag(R0); |
| 1469 __ Ret(); | 1424 __ Ret(); |
| 1470 | 1425 |
| 1471 __ Bind(&fall_through); | 1426 __ Bind(&fall_through); |
| 1472 return false; | |
| 1473 } | 1427 } |
| 1474 | 1428 |
| 1475 | 1429 |
| 1476 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { | 1430 void Intrinsifier::String_getIsEmpty(Assembler* assembler) { |
| 1477 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1431 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1478 __ ldr(R0, FieldAddress(R0, String::length_offset())); | 1432 __ ldr(R0, FieldAddress(R0, String::length_offset())); |
| 1479 __ cmp(R0, ShifterOperand(Smi::RawValue(0))); | 1433 __ cmp(R0, ShifterOperand(Smi::RawValue(0))); |
| 1480 __ LoadObject(R0, Bool::True(), EQ); | 1434 __ LoadObject(R0, Bool::True(), EQ); |
| 1481 __ LoadObject(R0, Bool::False(), NE); | 1435 __ LoadObject(R0, Bool::False(), NE); |
| 1482 __ Ret(); | 1436 __ Ret(); |
| 1483 return false; | |
| 1484 } | 1437 } |
| 1485 | 1438 |
| 1486 | 1439 |
| 1487 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1440 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
| 1488 __ ldr(R1, Address(SP, 0 * kWordSize)); | 1441 __ ldr(R1, Address(SP, 0 * kWordSize)); |
| 1489 __ ldr(R0, FieldAddress(R1, String::hash_offset())); | 1442 __ ldr(R0, FieldAddress(R1, String::hash_offset())); |
| 1490 __ cmp(R0, ShifterOperand(0)); | 1443 __ cmp(R0, ShifterOperand(0)); |
| 1491 __ bx(LR, NE); // Return if already computed. | 1444 __ bx(LR, NE); // Return if already computed. |
| 1492 | 1445 |
| 1493 __ ldr(R2, FieldAddress(R1, String::length_offset())); | 1446 __ ldr(R2, FieldAddress(R1, String::length_offset())); |
| 1494 | 1447 |
| 1495 Label done; | 1448 Label done; |
| 1496 // If the string is empty, set the hash to 1, and return. | 1449 // If the string is empty, set the hash to 1, and return. |
| 1497 __ cmp(R2, ShifterOperand(Smi::RawValue(0))); | 1450 __ cmp(R2, ShifterOperand(Smi::RawValue(0))); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1533 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1); | 1486 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1); |
| 1534 __ LoadImmediate(R2, (static_cast<intptr_t>(1) << String::kHashBits) - 1); | 1487 __ LoadImmediate(R2, (static_cast<intptr_t>(1) << String::kHashBits) - 1); |
| 1535 __ and_(R0, R0, ShifterOperand(R2)); | 1488 __ and_(R0, R0, ShifterOperand(R2)); |
| 1536 __ cmp(R0, ShifterOperand(0)); | 1489 __ cmp(R0, ShifterOperand(0)); |
| 1537 // return hash_ == 0 ? 1 : hash_; | 1490 // return hash_ == 0 ? 1 : hash_; |
| 1538 __ Bind(&done); | 1491 __ Bind(&done); |
| 1539 __ mov(R0, ShifterOperand(1), EQ); | 1492 __ mov(R0, ShifterOperand(1), EQ); |
| 1540 __ SmiTag(R0); | 1493 __ SmiTag(R0); |
| 1541 __ str(R0, FieldAddress(R1, String::hash_offset())); | 1494 __ str(R0, FieldAddress(R1, String::hash_offset())); |
| 1542 __ Ret(); | 1495 __ Ret(); |
| 1543 return true; | |
| 1544 } | 1496 } |
| 1545 | 1497 |
| 1546 | 1498 |
| 1547 // Allocates one-byte string of length 'end - start'. The content is not | 1499 // Allocates one-byte string of length 'end - start'. The content is not |
| 1548 // initialized. | 1500 // initialized. |
| 1549 // 'length-reg' (R2) contains tagged length. | 1501 // 'length-reg' (R2) contains tagged length. |
| 1550 // Returns new string as tagged pointer in R0. | 1502 // Returns new string as tagged pointer in R0. |
| 1551 static void TryAllocateOnebyteString(Assembler* assembler, | 1503 static void TryAllocateOnebyteString(Assembler* assembler, |
| 1552 Label* ok, | 1504 Label* ok, |
| 1553 Label* failure) { | 1505 Label* failure) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1616 | 1568 |
| 1617 __ Bind(&fail); | 1569 __ Bind(&fail); |
| 1618 __ b(failure); | 1570 __ b(failure); |
| 1619 } | 1571 } |
| 1620 | 1572 |
| 1621 | 1573 |
| 1622 // Arg0: Onebyte String | 1574 // Arg0: Onebyte String |
| 1623 // Arg1: Start index as Smi. | 1575 // Arg1: Start index as Smi. |
| 1624 // Arg2: End index as Smi. | 1576 // Arg2: End index as Smi. |
| 1625 // The indexes must be valid. | 1577 // The indexes must be valid. |
| 1626 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 1578 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
| 1627 const intptr_t kStringOffset = 2 * kWordSize; | 1579 const intptr_t kStringOffset = 2 * kWordSize; |
| 1628 const intptr_t kStartIndexOffset = 1 * kWordSize; | 1580 const intptr_t kStartIndexOffset = 1 * kWordSize; |
| 1629 const intptr_t kEndIndexOffset = 0 * kWordSize; | 1581 const intptr_t kEndIndexOffset = 0 * kWordSize; |
| 1630 Label fall_through, ok; | 1582 Label fall_through, ok; |
| 1631 | 1583 |
| 1632 __ ldr(R2, Address(SP, kEndIndexOffset)); | 1584 __ ldr(R2, Address(SP, kEndIndexOffset)); |
| 1633 __ ldr(TMP, Address(SP, kStartIndexOffset)); | 1585 __ ldr(TMP, Address(SP, kStartIndexOffset)); |
| 1634 __ sub(R2, R2, ShifterOperand(TMP)); | 1586 __ sub(R2, R2, ShifterOperand(TMP)); |
| 1635 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 1587 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 1636 __ Bind(&ok); | 1588 __ Bind(&ok); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1665 __ AddImmediate(R6, 1); | 1617 __ AddImmediate(R6, 1); |
| 1666 __ sub(R2, R2, ShifterOperand(1)); | 1618 __ sub(R2, R2, ShifterOperand(1)); |
| 1667 __ cmp(R2, ShifterOperand(0)); | 1619 __ cmp(R2, ShifterOperand(0)); |
| 1668 __ strb(R1, FieldAddress(R7, OneByteString::data_offset())); | 1620 __ strb(R1, FieldAddress(R7, OneByteString::data_offset())); |
| 1669 __ AddImmediate(R7, 1); | 1621 __ AddImmediate(R7, 1); |
| 1670 __ b(&loop, GT); | 1622 __ b(&loop, GT); |
| 1671 | 1623 |
| 1672 __ Bind(&done); | 1624 __ Bind(&done); |
| 1673 __ Ret(); | 1625 __ Ret(); |
| 1674 __ Bind(&fall_through); | 1626 __ Bind(&fall_through); |
| 1675 return false; | |
| 1676 } | 1627 } |
| 1677 | 1628 |
| 1678 | 1629 |
| 1679 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { | 1630 void Intrinsifier::OneByteString_setAt(Assembler* assembler) { |
| 1680 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 1631 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 1681 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 1632 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 1682 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString. | 1633 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString. |
| 1683 __ SmiUntag(R1); | 1634 __ SmiUntag(R1); |
| 1684 __ SmiUntag(R2); | 1635 __ SmiUntag(R2); |
| 1685 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag); | 1636 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag); |
| 1686 __ strb(R2, Address(R3, R1)); | 1637 __ strb(R2, Address(R3, R1)); |
| 1687 __ Ret(); | 1638 __ Ret(); |
| 1688 return true; | |
| 1689 } | 1639 } |
| 1690 | 1640 |
| 1691 | 1641 |
| 1692 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { | 1642 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { |
| 1693 __ ldr(R2, Address(SP, 0 * kWordSize)); // Length. | 1643 __ ldr(R2, Address(SP, 0 * kWordSize)); // Length. |
| 1694 Label fall_through, ok; | 1644 Label fall_through, ok; |
| 1695 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 1645 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 1696 | 1646 |
| 1697 __ Bind(&ok); | 1647 __ Bind(&ok); |
| 1698 __ Ret(); | 1648 __ Ret(); |
| 1699 | 1649 |
| 1700 __ Bind(&fall_through); | 1650 __ Bind(&fall_through); |
| 1701 return false; | |
| 1702 } | 1651 } |
| 1703 | 1652 |
| 1704 } // namespace dart | 1653 } // namespace dart |
| 1705 | 1654 |
| 1706 #endif // defined TARGET_ARCH_ARM | 1655 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |