| 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" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 __ CompareObject(R1, Object::null_object(), PP); | 59 __ CompareObject(R1, Object::null_object(), PP); |
| 60 __ b(&checked_ok, EQ); | 60 __ b(&checked_ok, EQ); |
| 61 | 61 |
| 62 // Check if it's dynamic. | 62 // Check if it's dynamic. |
| 63 // Get type at index 0. | 63 // Get type at index 0. |
| 64 __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0))); | 64 __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0))); |
| 65 __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()), PP); | 65 __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()), PP); |
| 66 __ b(&checked_ok, EQ); | 66 __ b(&checked_ok, EQ); |
| 67 | 67 |
| 68 // Check for int and num. | 68 // Check for int and num. |
| 69 __ tsti(R2, kSmiTagMask); // Value is Smi? | 69 __ tsti(R2, Immediate(Immediate(kSmiTagMask))); // Value is Smi? |
| 70 __ b(&fall_through, NE); // Non-smi value. | 70 __ b(&fall_through, NE); // Non-smi value. |
| 71 __ CompareObject(R0, Type::ZoneHandle(Type::IntType()), PP); | 71 __ CompareObject(R0, Type::ZoneHandle(Type::IntType()), PP); |
| 72 __ b(&checked_ok, EQ); | 72 __ b(&checked_ok, EQ); |
| 73 __ CompareObject(R0, Type::ZoneHandle(Type::Number()), PP); | 73 __ CompareObject(R0, Type::ZoneHandle(Type::Number()), PP); |
| 74 __ b(&fall_through, NE); | 74 __ b(&fall_through, NE); |
| 75 __ Bind(&checked_ok); | 75 __ Bind(&checked_ok); |
| 76 } | 76 } |
| 77 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 77 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 78 __ tsti(R1, kSmiTagMask); | 78 __ tsti(R1, Immediate(kSmiTagMask)); |
| 79 // Index not Smi. | 79 // Index not Smi. |
| 80 __ b(&fall_through, NE); | 80 __ b(&fall_through, NE); |
| 81 __ ldr(R0, Address(SP, 2 * kWordSize)); // Array. | 81 __ ldr(R0, Address(SP, 2 * kWordSize)); // Array. |
| 82 | 82 |
| 83 // Range check. | 83 // Range check. |
| 84 __ ldr(R3, FieldAddress(R0, Array::length_offset())); // Array length. | 84 __ ldr(R3, FieldAddress(R0, Array::length_offset())); // Array length. |
| 85 __ cmp(R1, Operand(R3)); | 85 __ cmp(R1, Operand(R3)); |
| 86 // Runtime throws exception. | 86 // Runtime throws exception. |
| 87 __ b(&fall_through, CS); | 87 __ b(&fall_through, CS); |
| 88 | 88 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 __ Bind(&fall_through); | 136 __ Bind(&fall_through); |
| 137 } | 137 } |
| 138 | 138 |
| 139 | 139 |
| 140 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { | 140 void Intrinsifier::GrowableArrayGetIndexed(Assembler* assembler) { |
| 141 Label fall_through; | 141 Label fall_through; |
| 142 | 142 |
| 143 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index | 143 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index |
| 144 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array | 144 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array |
| 145 | 145 |
| 146 __ tsti(R0, kSmiTagMask); | 146 __ tsti(R0, Immediate(kSmiTagMask)); |
| 147 __ b(&fall_through, NE); // Index is not an smi, fall through. | 147 __ b(&fall_through, NE); // Index is not an smi, fall through. |
| 148 | 148 |
| 149 // Range check. | 149 // Range check. |
| 150 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); | 150 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); |
| 151 __ cmp(R0, Operand(R6)); | 151 __ cmp(R0, Operand(R6)); |
| 152 __ b(&fall_through, CS); | 152 __ b(&fall_through, CS); |
| 153 | 153 |
| 154 ASSERT(kSmiTagShift == 1); | 154 ASSERT(kSmiTagShift == 1); |
| 155 // array element at R6 + R0 * 4 + Array::data_offset - 1 | 155 // array element at R6 + R0 * 4 + Array::data_offset - 1 |
| 156 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset())); // Data | 156 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset())); // Data |
| 157 __ add(R6, R6, Operand(R0, LSL, 2)); | 157 __ add(R6, R6, Operand(R0, LSL, 2)); |
| 158 __ ldr(R0, FieldAddress(R6, Array::data_offset())); | 158 __ ldr(R0, FieldAddress(R6, Array::data_offset())); |
| 159 __ ret(); | 159 __ ret(); |
| 160 __ Bind(&fall_through); | 160 __ Bind(&fall_through); |
| 161 } | 161 } |
| 162 | 162 |
| 163 | 163 |
| 164 // Set value into growable object array at specified index. | 164 // Set value into growable object array at specified index. |
| 165 // On stack: growable array (+2), index (+1), value (+0). | 165 // On stack: growable array (+2), index (+1), value (+0). |
| 166 void Intrinsifier::GrowableArraySetIndexed(Assembler* assembler) { | 166 void Intrinsifier::GrowableArraySetIndexed(Assembler* assembler) { |
| 167 if (FLAG_enable_type_checks) { | 167 if (FLAG_enable_type_checks) { |
| 168 return; | 168 return; |
| 169 } | 169 } |
| 170 Label fall_through; | 170 Label fall_through; |
| 171 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. | 171 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. |
| 172 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. | 172 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. |
| 173 __ tsti(R1, kSmiTagMask); | 173 __ tsti(R1, Immediate(kSmiTagMask)); |
| 174 __ b(&fall_through, NE); // Non-smi index. | 174 __ b(&fall_through, NE); // Non-smi index. |
| 175 // Range check using _length field. | 175 // Range check using _length field. |
| 176 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); | 176 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 177 __ cmp(R1, Operand(R2)); | 177 __ cmp(R1, Operand(R2)); |
| 178 // Runtime throws exception. | 178 // Runtime throws exception. |
| 179 __ b(&fall_through, CS); | 179 __ b(&fall_through, CS); |
| 180 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. | 180 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. |
| 181 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 181 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| 182 // Note that R1 is Smi, i.e, times 2. | 182 // Note that R1 is Smi, i.e, times 2. |
| 183 ASSERT(kSmiTagShift == 1); | 183 ASSERT(kSmiTagShift == 1); |
| 184 __ add(R1, R0, Operand(R1, LSL, 2)); | 184 __ add(R1, R0, Operand(R1, LSL, 2)); |
| 185 __ StoreIntoObject(R0, | 185 __ StoreIntoObject(R0, |
| 186 FieldAddress(R1, Array::data_offset()), | 186 FieldAddress(R1, Array::data_offset()), |
| 187 R2); | 187 R2); |
| 188 __ ret(); | 188 __ ret(); |
| 189 __ Bind(&fall_through); | 189 __ Bind(&fall_through); |
| 190 } | 190 } |
| 191 | 191 |
| 192 | 192 |
| 193 // Set length of growable object array. The length cannot | 193 // Set length of growable object array. The length cannot |
| 194 // be greater than the length of the data container. | 194 // be greater than the length of the data container. |
| 195 // On stack: growable array (+1), length (+0). | 195 // On stack: growable array (+1), length (+0). |
| 196 void Intrinsifier::GrowableArraySetLength(Assembler* assembler) { | 196 void Intrinsifier::GrowableArraySetLength(Assembler* assembler) { |
| 197 Label fall_through; | 197 Label fall_through; |
| 198 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 198 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 199 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. | 199 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. |
| 200 __ tsti(R1, kSmiTagMask); // Check for Smi. | 200 __ tsti(R1, Immediate(kSmiTagMask)); // Check for Smi. |
| 201 __ b(&fall_through, NE); | 201 __ b(&fall_through, NE); |
| 202 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); | 202 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); |
| 203 __ ret(); | 203 __ ret(); |
| 204 __ Bind(&fall_through); | 204 __ Bind(&fall_through); |
| 205 // Fall through on non-Smi. | 205 // Fall through on non-Smi. |
| 206 } | 206 } |
| 207 | 207 |
| 208 | 208 |
| 209 // Set data of growable object array. | 209 // Set data of growable object array. |
| 210 // On stack: growable array (+1), data (+0). | 210 // On stack: growable array (+1), data (+0). |
| 211 void Intrinsifier::GrowableArraySetData(Assembler* assembler) { | 211 void Intrinsifier::GrowableArraySetData(Assembler* assembler) { |
| 212 if (FLAG_enable_type_checks) { | 212 if (FLAG_enable_type_checks) { |
| 213 return; | 213 return; |
| 214 } | 214 } |
| 215 Label fall_through; | 215 Label fall_through; |
| 216 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. | 216 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. |
| 217 // Check that data is an ObjectArray. | 217 // Check that data is an ObjectArray. |
| 218 __ tsti(R1, kSmiTagMask); | 218 __ tsti(R1, Immediate(kSmiTagMask)); |
| 219 __ b(&fall_through, EQ); // Data is Smi. | 219 __ b(&fall_through, EQ); // Data is Smi. |
| 220 __ CompareClassId(R1, kArrayCid, kNoPP); | 220 __ CompareClassId(R1, kArrayCid, kNoPP); |
| 221 __ b(&fall_through, NE); | 221 __ b(&fall_through, NE); |
| 222 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. | 222 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. |
| 223 __ StoreIntoObject(R0, | 223 __ StoreIntoObject(R0, |
| 224 FieldAddress(R0, GrowableObjectArray::data_offset()), | 224 FieldAddress(R0, GrowableObjectArray::data_offset()), |
| 225 R1); | 225 R1); |
| 226 __ ret(); | 226 __ ret(); |
| 227 __ Bind(&fall_through); | 227 __ Bind(&fall_through); |
| 228 } | 228 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 return -1; | 276 return -1; |
| 277 } | 277 } |
| 278 | 278 |
| 279 | 279 |
| 280 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ | 280 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ |
| 281 Label fall_through; \ | 281 Label fall_through; \ |
| 282 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ | 282 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ |
| 283 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ | 283 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ |
| 284 /* Check that length is a positive Smi. */ \ | 284 /* Check that length is a positive Smi. */ \ |
| 285 /* R2: requested array length argument. */ \ | 285 /* R2: requested array length argument. */ \ |
| 286 __ tsti(R2, kSmiTagMask); \ | 286 __ tsti(R2, Immediate(kSmiTagMask)); \ |
| 287 __ b(&fall_through, NE); \ | 287 __ b(&fall_through, NE); \ |
| 288 __ CompareRegisters(R2, ZR); \ | 288 __ CompareRegisters(R2, ZR); \ |
| 289 __ b(&fall_through, LT); \ | 289 __ b(&fall_through, LT); \ |
| 290 __ SmiUntag(R2); \ | 290 __ SmiUntag(R2); \ |
| 291 /* Check for maximum allowed length. */ \ | 291 /* Check for maximum allowed length. */ \ |
| 292 /* R2: untagged array length. */ \ | 292 /* R2: untagged array length. */ \ |
| 293 __ CompareImmediate(R2, max_len, kNoPP); \ | 293 __ CompareImmediate(R2, max_len, kNoPP); \ |
| 294 __ b(&fall_through, GT); \ | 294 __ b(&fall_through, GT); \ |
| 295 __ LslImmediate(R2, R2, scale_shift); \ | 295 __ LslImmediate(R2, R2, scale_shift); \ |
| 296 const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \ | 296 const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \ |
| 297 __ AddImmediate(R2, R2, fixed_size, kNoPP); \ | 297 __ AddImmediate(R2, R2, fixed_size, kNoPP); \ |
| 298 __ andi(R2, R2, ~(kObjectAlignment - 1)); \ | 298 __ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); \ |
| 299 Heap* heap = Isolate::Current()->heap(); \ | 299 Heap* heap = Isolate::Current()->heap(); \ |
| 300 Heap::Space space = heap->SpaceForAllocation(cid); \ | 300 Heap::Space space = heap->SpaceForAllocation(cid); \ |
| 301 __ LoadImmediate(R0, heap->TopAddress(space), kNoPP); \ | 301 __ LoadImmediate(R0, heap->TopAddress(space), kNoPP); \ |
| 302 __ ldr(R0, Address(R0, 0)); \ | 302 __ ldr(R0, Address(R0, 0)); \ |
| 303 \ | 303 \ |
| 304 /* R2: allocation size. */ \ | 304 /* R2: allocation size. */ \ |
| 305 __ add(R1, R0, Operand(R2)); \ | 305 __ add(R1, R0, Operand(R2)); \ |
| 306 __ b(&fall_through, VS); \ | 306 __ b(&fall_through, VS); \ |
| 307 \ | 307 \ |
| 308 /* Check if the allocation fits into the remaining space. */ \ | 308 /* Check if the allocation fits into the remaining space. */ \ |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 378 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
| 379 #undef TYPED_DATA_ALLOCATOR | 379 #undef TYPED_DATA_ALLOCATOR |
| 380 | 380 |
| 381 | 381 |
| 382 // Loads args from stack into R0 and R1 | 382 // Loads args from stack into R0 and R1 |
| 383 // Tests if they are smis, jumps to label not_smi if not. | 383 // Tests if they are smis, jumps to label not_smi if not. |
| 384 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 384 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 385 __ ldr(R0, Address(SP, + 0 * kWordSize)); | 385 __ ldr(R0, Address(SP, + 0 * kWordSize)); |
| 386 __ ldr(R1, Address(SP, + 1 * kWordSize)); | 386 __ ldr(R1, Address(SP, + 1 * kWordSize)); |
| 387 __ orr(TMP, R0, Operand(R1)); | 387 __ orr(TMP, R0, Operand(R1)); |
| 388 __ tsti(TMP, kSmiTagMask); | 388 __ tsti(TMP, Immediate(kSmiTagMask)); |
| 389 __ b(not_smi, NE); | 389 __ b(not_smi, NE); |
| 390 } | 390 } |
| 391 | 391 |
| 392 | 392 |
| 393 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 393 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
| 394 Label fall_through; | 394 Label fall_through; |
| 395 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. | 395 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. |
| 396 __ adds(R0, R0, Operand(R1)); // Adds. | 396 __ adds(R0, R0, Operand(R1)); // Adds. |
| 397 __ b(&fall_through, VS); // Fall-through on overflow. | 397 __ b(&fall_through, VS); // Fall-through on overflow. |
| 398 __ ret(); | 398 __ ret(); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 // } else { | 503 // } else { |
| 504 // res = res + right; | 504 // res = res + right; |
| 505 // } | 505 // } |
| 506 // } | 506 // } |
| 507 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 507 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
| 508 // Check to see if we have integer division | 508 // Check to see if we have integer division |
| 509 Label neg_remainder, fall_through; | 509 Label neg_remainder, fall_through; |
| 510 __ ldr(R1, Address(SP, + 0 * kWordSize)); | 510 __ ldr(R1, Address(SP, + 0 * kWordSize)); |
| 511 __ ldr(R0, Address(SP, + 1 * kWordSize)); | 511 __ ldr(R0, Address(SP, + 1 * kWordSize)); |
| 512 __ orr(TMP, R0, Operand(R1)); | 512 __ orr(TMP, R0, Operand(R1)); |
| 513 __ tsti(TMP, kSmiTagMask); | 513 __ tsti(TMP, Immediate(kSmiTagMask)); |
| 514 __ b(&fall_through, NE); | 514 __ b(&fall_through, NE); |
| 515 // R1: Tagged left (dividend). | 515 // R1: Tagged left (dividend). |
| 516 // R0: Tagged right (divisor). | 516 // R0: Tagged right (divisor). |
| 517 // Check if modulo by zero -> exception thrown in main function. | 517 // Check if modulo by zero -> exception thrown in main function. |
| 518 __ CompareRegisters(R0, ZR); | 518 __ CompareRegisters(R0, ZR); |
| 519 __ b(&fall_through, EQ); | 519 __ b(&fall_through, EQ); |
| 520 EmitRemainderOperation(assembler); | 520 EmitRemainderOperation(assembler); |
| 521 // Untagged right in R0. Untagged remainder result in R1. | 521 // Untagged right in R0. Untagged remainder result in R1. |
| 522 | 522 |
| 523 __ CompareRegisters(R1, ZR); | 523 __ CompareRegisters(R1, ZR); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 __ b(&fall_through, EQ); | 557 __ b(&fall_through, EQ); |
| 558 __ SmiTag(R0); // Not equal. Okay to tag and return. | 558 __ SmiTag(R0); // Not equal. Okay to tag and return. |
| 559 __ ret(); // Return. | 559 __ ret(); // Return. |
| 560 __ Bind(&fall_through); | 560 __ Bind(&fall_through); |
| 561 } | 561 } |
| 562 | 562 |
| 563 | 563 |
| 564 void Intrinsifier::Integer_negate(Assembler* assembler) { | 564 void Intrinsifier::Integer_negate(Assembler* assembler) { |
| 565 Label fall_through; | 565 Label fall_through; |
| 566 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument. | 566 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument. |
| 567 __ tsti(R0, kSmiTagMask); // Test for Smi. | 567 __ tsti(R0, Immediate(kSmiTagMask)); // Test for Smi. |
| 568 __ b(&fall_through, NE); | 568 __ b(&fall_through, NE); |
| 569 __ negs(R0, R0); | 569 __ negs(R0, R0); |
| 570 __ b(&fall_through, VS); | 570 __ b(&fall_through, VS); |
| 571 __ ret(); | 571 __ ret(); |
| 572 __ Bind(&fall_through); | 572 __ Bind(&fall_through); |
| 573 } | 573 } |
| 574 | 574 |
| 575 | 575 |
| 576 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 576 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
| 577 Label fall_through; | 577 Label fall_through; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 // can be Smi, Mint, Bigint or double. | 687 // can be Smi, Mint, Bigint or double. |
| 688 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 688 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
| 689 Label fall_through, true_label, check_for_mint; | 689 Label fall_through, true_label, check_for_mint; |
| 690 // For integer receiver '===' check first. | 690 // For integer receiver '===' check first. |
| 691 __ ldr(R0, Address(SP, 0 * kWordSize)); | 691 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 692 __ ldr(R1, Address(SP, 1 * kWordSize)); | 692 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| 693 __ cmp(R0, Operand(R1)); | 693 __ cmp(R0, Operand(R1)); |
| 694 __ b(&true_label, EQ); | 694 __ b(&true_label, EQ); |
| 695 | 695 |
| 696 __ orr(R2, R0, Operand(R1)); | 696 __ orr(R2, R0, Operand(R1)); |
| 697 __ tsti(R2, kSmiTagMask); | 697 __ tsti(R2, Immediate(kSmiTagMask)); |
| 698 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks. | 698 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks. |
| 699 | 699 |
| 700 // Both arguments are smi, '===' is good enough. | 700 // Both arguments are smi, '===' is good enough. |
| 701 __ LoadObject(R0, Bool::False(), PP); | 701 __ LoadObject(R0, Bool::False(), PP); |
| 702 __ ret(); | 702 __ ret(); |
| 703 __ Bind(&true_label); | 703 __ Bind(&true_label); |
| 704 __ LoadObject(R0, Bool::True(), PP); | 704 __ LoadObject(R0, Bool::True(), PP); |
| 705 __ ret(); | 705 __ ret(); |
| 706 | 706 |
| 707 // At least one of the arguments was not Smi. | 707 // At least one of the arguments was not Smi. |
| 708 Label receiver_not_smi; | 708 Label receiver_not_smi; |
| 709 __ Bind(&check_for_mint); | 709 __ Bind(&check_for_mint); |
| 710 | 710 |
| 711 __ tsti(R1, kSmiTagMask); // Check receiver. | 711 __ tsti(R1, Immediate(kSmiTagMask)); // Check receiver. |
| 712 __ b(&receiver_not_smi, NE); | 712 __ b(&receiver_not_smi, NE); |
| 713 | 713 |
| 714 // Left (receiver) is Smi, return false if right is not Double. | 714 // Left (receiver) is Smi, return false if right is not Double. |
| 715 // Note that an instance of Mint or Bigint never contains a value that can be | 715 // Note that an instance of Mint or Bigint never contains a value that can be |
| 716 // represented by Smi. | 716 // represented by Smi. |
| 717 | 717 |
| 718 __ CompareClassId(R0, kDoubleCid, kNoPP); | 718 __ CompareClassId(R0, kDoubleCid, kNoPP); |
| 719 __ b(&fall_through, EQ); | 719 __ b(&fall_through, EQ); |
| 720 __ LoadObject(R0, Bool::False(), PP); // Smi == Mint -> false. | 720 __ LoadObject(R0, Bool::False(), PP); // Smi == Mint -> false. |
| 721 __ ret(); | 721 __ ret(); |
| 722 | 722 |
| 723 __ Bind(&receiver_not_smi); | 723 __ Bind(&receiver_not_smi); |
| 724 // R1: receiver. | 724 // R1: receiver. |
| 725 | 725 |
| 726 __ CompareClassId(R1, kMintCid, kNoPP); | 726 __ CompareClassId(R1, kMintCid, kNoPP); |
| 727 __ b(&fall_through, NE); | 727 __ b(&fall_through, NE); |
| 728 // Receiver is Mint, return false if right is Smi. | 728 // Receiver is Mint, return false if right is Smi. |
| 729 __ tsti(R0, kSmiTagMask); | 729 __ tsti(R0, Immediate(kSmiTagMask)); |
| 730 __ b(&fall_through, NE); | 730 __ b(&fall_through, NE); |
| 731 __ LoadObject(R0, Bool::False(), PP); | 731 __ LoadObject(R0, Bool::False(), PP); |
| 732 __ ret(); | 732 __ ret(); |
| 733 // TODO(srdjan): Implement Mint == Mint comparison. | 733 // TODO(srdjan): Implement Mint == Mint comparison. |
| 734 | 734 |
| 735 __ Bind(&fall_through); | 735 __ Bind(&fall_through); |
| 736 } | 736 } |
| 737 | 737 |
| 738 | 738 |
| 739 void Intrinsifier::Integer_equal(Assembler* assembler) { | 739 void Intrinsifier::Integer_equal(Assembler* assembler) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 760 __ asrv(R0, R1, R0); | 760 __ asrv(R0, R1, R0); |
| 761 __ SmiTag(R0); | 761 __ SmiTag(R0); |
| 762 __ ret(); | 762 __ ret(); |
| 763 __ Bind(&fall_through); | 763 __ Bind(&fall_through); |
| 764 } | 764 } |
| 765 | 765 |
| 766 | 766 |
| 767 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 767 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
| 768 __ ldr(R0, Address(SP, 0 * kWordSize)); | 768 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 769 __ mvn(R0, R0); | 769 __ mvn(R0, R0); |
| 770 __ andi(R0, R0, ~kSmiTagMask); // Remove inverted smi-tag. | 770 __ andi(R0, R0, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 771 __ ret(); | 771 __ ret(); |
| 772 } | 772 } |
| 773 | 773 |
| 774 | 774 |
| 775 void Intrinsifier::Smi_bitLength(Assembler* assembler) { | 775 void Intrinsifier::Smi_bitLength(Assembler* assembler) { |
| 776 // TODO(sra): Implement as word-length - CLZ. | 776 // TODO(sra): Implement as word-length - CLZ. |
| 777 } | 777 } |
| 778 | 778 |
| 779 | 779 |
| 780 void Intrinsifier::Bigint_setNeg(Assembler* assembler) { | 780 void Intrinsifier::Bigint_setNeg(Assembler* assembler) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 831 } | 831 } |
| 832 | 832 |
| 833 | 833 |
| 834 // Check if the last argument is a double, jump to label 'is_smi' if smi | 834 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 835 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 835 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 836 // Returns the last argument in R0. | 836 // Returns the last argument in R0. |
| 837 static void TestLastArgumentIsDouble(Assembler* assembler, | 837 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 838 Label* is_smi, | 838 Label* is_smi, |
| 839 Label* not_double_smi) { | 839 Label* not_double_smi) { |
| 840 __ ldr(R0, Address(SP, 0 * kWordSize)); | 840 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 841 __ tsti(R0, kSmiTagMask); | 841 __ tsti(R0, Immediate(kSmiTagMask)); |
| 842 __ b(is_smi, EQ); | 842 __ b(is_smi, EQ); |
| 843 __ CompareClassId(R0, kDoubleCid, kNoPP); | 843 __ CompareClassId(R0, kDoubleCid, kNoPP); |
| 844 __ b(not_double_smi, NE); | 844 __ b(not_double_smi, NE); |
| 845 // Fall through with Double in R0. | 845 // Fall through with Double in R0. |
| 846 } | 846 } |
| 847 | 847 |
| 848 | 848 |
| 849 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 849 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
| 850 // type. Return true or false object in the register R0. Any NaN argument | 850 // type. Return true or false object in the register R0. Any NaN argument |
| 851 // returns false. Any non-double arg1 causes control flow to fall through to the | 851 // returns false. Any non-double arg1 causes control flow to fall through to the |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 948 void Intrinsifier::Double_div(Assembler* assembler) { | 948 void Intrinsifier::Double_div(Assembler* assembler) { |
| 949 DoubleArithmeticOperations(assembler, Token::kDIV); | 949 DoubleArithmeticOperations(assembler, Token::kDIV); |
| 950 } | 950 } |
| 951 | 951 |
| 952 | 952 |
| 953 // Left is double right is integer (Bigint, Mint or Smi) | 953 // Left is double right is integer (Bigint, Mint or Smi) |
| 954 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 954 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 955 Label fall_through; | 955 Label fall_through; |
| 956 // Only smis allowed. | 956 // Only smis allowed. |
| 957 __ ldr(R0, Address(SP, 0 * kWordSize)); | 957 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 958 __ tsti(R0, kSmiTagMask); | 958 __ tsti(R0, Immediate(kSmiTagMask)); |
| 959 __ b(&fall_through, NE); | 959 __ b(&fall_through, NE); |
| 960 // Is Smi. | 960 // Is Smi. |
| 961 __ SmiUntag(R0); | 961 __ SmiUntag(R0); |
| 962 __ scvtfd(V1, R0); | 962 __ scvtfd(V1, R0); |
| 963 __ ldr(R0, Address(SP, 1 * kWordSize)); | 963 __ ldr(R0, Address(SP, 1 * kWordSize)); |
| 964 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); | 964 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); |
| 965 __ fmuld(V0, V0, V1); | 965 __ fmuld(V0, V0, V1); |
| 966 const Class& double_class = Class::Handle( | 966 const Class& double_class = Class::Handle( |
| 967 Isolate::Current()->object_store()->double_class()); | 967 Isolate::Current()->object_store()->double_class()); |
| 968 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); | 968 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); |
| 969 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); | 969 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); |
| 970 __ ret(); | 970 __ ret(); |
| 971 __ Bind(&fall_through); | 971 __ Bind(&fall_through); |
| 972 } | 972 } |
| 973 | 973 |
| 974 | 974 |
| 975 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { | 975 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { |
| 976 Label fall_through; | 976 Label fall_through; |
| 977 | 977 |
| 978 __ ldr(R0, Address(SP, 0 * kWordSize)); | 978 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 979 __ tsti(R0, kSmiTagMask); | 979 __ tsti(R0, Immediate(kSmiTagMask)); |
| 980 __ b(&fall_through, NE); | 980 __ b(&fall_through, NE); |
| 981 // Is Smi. | 981 // Is Smi. |
| 982 __ SmiUntag(R0); | 982 __ SmiUntag(R0); |
| 983 __ scvtfd(V0, R0); | 983 __ scvtfd(V0, R0); |
| 984 const Class& double_class = Class::Handle( | 984 const Class& double_class = Class::Handle( |
| 985 Isolate::Current()->object_store()->double_class()); | 985 Isolate::Current()->object_store()->double_class()); |
| 986 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); | 986 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); |
| 987 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); | 987 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); |
| 988 __ ret(); | 988 __ ret(); |
| 989 __ Bind(&fall_through); | 989 __ Bind(&fall_through); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1019 __ Bind(&is_true); | 1019 __ Bind(&is_true); |
| 1020 __ mov(R0, true_reg); | 1020 __ mov(R0, true_reg); |
| 1021 | 1021 |
| 1022 __ Bind(&is_false); | 1022 __ Bind(&is_false); |
| 1023 __ ret(); | 1023 __ ret(); |
| 1024 | 1024 |
| 1025 __ Bind(&is_zero); | 1025 __ Bind(&is_zero); |
| 1026 // Check for negative zero by looking at the sign bit. | 1026 // Check for negative zero by looking at the sign bit. |
| 1027 __ fmovrd(R1, V0); | 1027 __ fmovrd(R1, V0); |
| 1028 __ LsrImmediate(R1, R1, 63); | 1028 __ LsrImmediate(R1, R1, 63); |
| 1029 __ tsti(R1, 1); | 1029 __ tsti(R1, Immediate(1)); |
| 1030 __ csel(R0, true_reg, false_reg, NE); // Sign bit set. | 1030 __ csel(R0, true_reg, false_reg, NE); // Sign bit set. |
| 1031 __ ret(); | 1031 __ ret(); |
| 1032 } | 1032 } |
| 1033 | 1033 |
| 1034 | 1034 |
| 1035 void Intrinsifier::DoubleToInteger(Assembler* assembler) { | 1035 void Intrinsifier::DoubleToInteger(Assembler* assembler) { |
| 1036 Label fall_through; | 1036 Label fall_through; |
| 1037 | 1037 |
| 1038 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1038 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1039 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); | 1039 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver. | 1096 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver. |
| 1097 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'. | 1097 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'. |
| 1098 | 1098 |
| 1099 // Addresses of _state[0]. | 1099 // Addresses of _state[0]. |
| 1100 const int64_t disp = | 1100 const int64_t disp = |
| 1101 Instance::DataOffsetFor(kTypedDataUint32ArrayCid) - kHeapObjectTag; | 1101 Instance::DataOffsetFor(kTypedDataUint32ArrayCid) - kHeapObjectTag; |
| 1102 | 1102 |
| 1103 __ LoadImmediate(R0, a_int_value, kNoPP); | 1103 __ LoadImmediate(R0, a_int_value, kNoPP); |
| 1104 __ LoadFromOffset(R2, R1, disp, kNoPP); | 1104 __ LoadFromOffset(R2, R1, disp, kNoPP); |
| 1105 __ LsrImmediate(R3, R2, 32); | 1105 __ LsrImmediate(R3, R2, 32); |
| 1106 __ andi(R2, R2, 0xffffffff); | 1106 __ andi(R2, R2, Immediate(0xffffffff)); |
| 1107 __ mul(R2, R0, R2); | 1107 __ mul(R2, R0, R2); |
| 1108 __ add(R2, R2, Operand(R3)); | 1108 __ add(R2, R2, Operand(R3)); |
| 1109 __ StoreToOffset(R2, R1, disp, kNoPP); | 1109 __ StoreToOffset(R2, R1, disp, kNoPP); |
| 1110 __ ret(); | 1110 __ ret(); |
| 1111 } | 1111 } |
| 1112 | 1112 |
| 1113 | 1113 |
| 1114 void Intrinsifier::ObjectEquals(Assembler* assembler) { | 1114 void Intrinsifier::ObjectEquals(Assembler* assembler) { |
| 1115 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1115 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1116 __ ldr(R1, Address(SP, 1 * kWordSize)); | 1116 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1132 // Hash not yet computed. | 1132 // Hash not yet computed. |
| 1133 __ Bind(&fall_through); | 1133 __ Bind(&fall_through); |
| 1134 } | 1134 } |
| 1135 | 1135 |
| 1136 | 1136 |
| 1137 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { | 1137 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { |
| 1138 Label fall_through, try_two_byte_string; | 1138 Label fall_through, try_two_byte_string; |
| 1139 | 1139 |
| 1140 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1140 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1141 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1141 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1142 __ tsti(R1, kSmiTagMask); | 1142 __ tsti(R1, Immediate(kSmiTagMask)); |
| 1143 __ b(&fall_through, NE); // Index is not a Smi. | 1143 __ b(&fall_through, NE); // Index is not a Smi. |
| 1144 // Range check. | 1144 // Range check. |
| 1145 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1145 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1146 __ cmp(R1, Operand(R2)); | 1146 __ cmp(R1, Operand(R2)); |
| 1147 __ b(&fall_through, CS); // Runtime throws exception. | 1147 __ b(&fall_through, CS); // Runtime throws exception. |
| 1148 __ CompareClassId(R0, kOneByteStringCid, kNoPP); | 1148 __ CompareClassId(R0, kOneByteStringCid, kNoPP); |
| 1149 __ b(&try_two_byte_string, NE); | 1149 __ b(&try_two_byte_string, NE); |
| 1150 __ SmiUntag(R1); | 1150 __ SmiUntag(R1); |
| 1151 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); | 1151 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); |
| 1152 __ ldr(R0, Address(R0, R1), kUnsignedByte); | 1152 __ ldr(R0, Address(R0, R1), kUnsignedByte); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1164 | 1164 |
| 1165 __ Bind(&fall_through); | 1165 __ Bind(&fall_through); |
| 1166 } | 1166 } |
| 1167 | 1167 |
| 1168 | 1168 |
| 1169 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { | 1169 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { |
| 1170 Label fall_through, try_two_byte_string; | 1170 Label fall_through, try_two_byte_string; |
| 1171 | 1171 |
| 1172 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1172 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1173 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1173 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1174 __ tsti(R1, kSmiTagMask); | 1174 __ tsti(R1, Immediate(kSmiTagMask)); |
| 1175 __ b(&fall_through, NE); // Index is not a Smi. | 1175 __ b(&fall_through, NE); // Index is not a Smi. |
| 1176 // Range check. | 1176 // Range check. |
| 1177 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1177 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1178 __ cmp(R1, Operand(R2)); | 1178 __ cmp(R1, Operand(R2)); |
| 1179 __ b(&fall_through, CS); // Runtime throws exception. | 1179 __ b(&fall_through, CS); // Runtime throws exception. |
| 1180 | 1180 |
| 1181 __ CompareClassId(R0, kOneByteStringCid, kNoPP); | 1181 __ CompareClassId(R0, kOneByteStringCid, kNoPP); |
| 1182 __ b(&try_two_byte_string, NE); | 1182 __ b(&try_two_byte_string, NE); |
| 1183 __ SmiUntag(R1); | 1183 __ SmiUntag(R1); |
| 1184 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); | 1184 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1290 static void TryAllocateOnebyteString(Assembler* assembler, | 1290 static void TryAllocateOnebyteString(Assembler* assembler, |
| 1291 Label* ok, | 1291 Label* ok, |
| 1292 Label* failure) { | 1292 Label* failure) { |
| 1293 const Register length_reg = R2; | 1293 const Register length_reg = R2; |
| 1294 Label fail; | 1294 Label fail; |
| 1295 | 1295 |
| 1296 __ mov(R6, length_reg); // Save the length register. | 1296 __ mov(R6, length_reg); // Save the length register. |
| 1297 __ SmiUntag(length_reg); | 1297 __ SmiUntag(length_reg); |
| 1298 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; | 1298 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; |
| 1299 __ AddImmediate(length_reg, length_reg, fixed_size, kNoPP); | 1299 __ AddImmediate(length_reg, length_reg, fixed_size, kNoPP); |
| 1300 __ andi(length_reg, length_reg, ~(kObjectAlignment - 1)); | 1300 __ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1))); |
| 1301 | 1301 |
| 1302 Isolate* isolate = Isolate::Current(); | 1302 Isolate* isolate = Isolate::Current(); |
| 1303 Heap* heap = isolate->heap(); | 1303 Heap* heap = isolate->heap(); |
| 1304 const intptr_t cid = kOneByteStringCid; | 1304 const intptr_t cid = kOneByteStringCid; |
| 1305 Heap::Space space = heap->SpaceForAllocation(cid); | 1305 Heap::Space space = heap->SpaceForAllocation(cid); |
| 1306 __ LoadImmediate(R3, heap->TopAddress(space), kNoPP); | 1306 __ LoadImmediate(R3, heap->TopAddress(space), kNoPP); |
| 1307 __ ldr(R0, Address(R3)); | 1307 __ ldr(R0, Address(R3)); |
| 1308 | 1308 |
| 1309 // length_reg: allocation size. | 1309 // length_reg: allocation size. |
| 1310 __ adds(R1, R0, Operand(length_reg)); | 1310 __ adds(R1, R0, Operand(length_reg)); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 // The indexes must be valid. | 1364 // The indexes must be valid. |
| 1365 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 1365 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
| 1366 const intptr_t kStringOffset = 2 * kWordSize; | 1366 const intptr_t kStringOffset = 2 * kWordSize; |
| 1367 const intptr_t kStartIndexOffset = 1 * kWordSize; | 1367 const intptr_t kStartIndexOffset = 1 * kWordSize; |
| 1368 const intptr_t kEndIndexOffset = 0 * kWordSize; | 1368 const intptr_t kEndIndexOffset = 0 * kWordSize; |
| 1369 Label fall_through, ok; | 1369 Label fall_through, ok; |
| 1370 | 1370 |
| 1371 __ ldr(R2, Address(SP, kEndIndexOffset)); | 1371 __ ldr(R2, Address(SP, kEndIndexOffset)); |
| 1372 __ ldr(TMP, Address(SP, kStartIndexOffset)); | 1372 __ ldr(TMP, Address(SP, kStartIndexOffset)); |
| 1373 __ orr(R3, R2, Operand(TMP)); | 1373 __ orr(R3, R2, Operand(TMP)); |
| 1374 __ tsti(R3, kSmiTagMask); | 1374 __ tsti(R3, Immediate(kSmiTagMask)); |
| 1375 __ b(&fall_through, NE); // 'start', 'end' not Smi. | 1375 __ b(&fall_through, NE); // 'start', 'end' not Smi. |
| 1376 | 1376 |
| 1377 __ sub(R2, R2, Operand(TMP)); | 1377 __ sub(R2, R2, Operand(TMP)); |
| 1378 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 1378 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 1379 __ Bind(&ok); | 1379 __ Bind(&ok); |
| 1380 // R0: new string as tagged pointer. | 1380 // R0: new string as tagged pointer. |
| 1381 // Copy string. | 1381 // Copy string. |
| 1382 __ ldr(R3, Address(SP, kStringOffset)); | 1382 __ ldr(R3, Address(SP, kStringOffset)); |
| 1383 __ ldr(R1, Address(SP, kStartIndexOffset)); | 1383 __ ldr(R1, Address(SP, kStartIndexOffset)); |
| 1384 __ SmiUntag(R1); | 1384 __ SmiUntag(R1); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1447 void StringEquality(Assembler* assembler, intptr_t string_cid) { | 1447 void StringEquality(Assembler* assembler, intptr_t string_cid) { |
| 1448 Label fall_through, is_true, is_false, loop; | 1448 Label fall_through, is_true, is_false, loop; |
| 1449 __ ldr(R0, Address(SP, 1 * kWordSize)); // This. | 1449 __ ldr(R0, Address(SP, 1 * kWordSize)); // This. |
| 1450 __ ldr(R1, Address(SP, 0 * kWordSize)); // Other. | 1450 __ ldr(R1, Address(SP, 0 * kWordSize)); // Other. |
| 1451 | 1451 |
| 1452 // Are identical? | 1452 // Are identical? |
| 1453 __ cmp(R0, Operand(R1)); | 1453 __ cmp(R0, Operand(R1)); |
| 1454 __ b(&is_true, EQ); | 1454 __ b(&is_true, EQ); |
| 1455 | 1455 |
| 1456 // Is other OneByteString? | 1456 // Is other OneByteString? |
| 1457 __ tsti(R1, kSmiTagMask); | 1457 __ tsti(R1, Immediate(kSmiTagMask)); |
| 1458 __ b(&fall_through, EQ); | 1458 __ b(&fall_through, EQ); |
| 1459 __ CompareClassId(R1, string_cid, kNoPP); | 1459 __ CompareClassId(R1, string_cid, kNoPP); |
| 1460 __ b(&fall_through, NE); | 1460 __ b(&fall_through, NE); |
| 1461 | 1461 |
| 1462 // Have same length? | 1462 // Have same length? |
| 1463 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1463 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1464 __ ldr(R3, FieldAddress(R1, String::length_offset())); | 1464 __ ldr(R3, FieldAddress(R1, String::length_offset())); |
| 1465 __ cmp(R2, Operand(R3)); | 1465 __ cmp(R2, Operand(R3)); |
| 1466 __ b(&is_false, NE); | 1466 __ b(&is_false, NE); |
| 1467 | 1467 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1552 Isolate* isolate = Isolate::Current(); | 1552 Isolate* isolate = Isolate::Current(); |
| 1553 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); | 1553 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); |
| 1554 // Set return value to Isolate::current_tag_. | 1554 // Set return value to Isolate::current_tag_. |
| 1555 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); | 1555 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); |
| 1556 __ ret(); | 1556 __ ret(); |
| 1557 } | 1557 } |
| 1558 | 1558 |
| 1559 } // namespace dart | 1559 } // namespace dart |
| 1560 | 1560 |
| 1561 #endif // defined TARGET_ARCH_ARM64 | 1561 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |