| 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 30 matching lines...) Expand all Loading... |
| 811 } | 811 } |
| 812 | 812 |
| 813 | 813 |
| 814 // Check if the last argument is a double, jump to label 'is_smi' if smi | 814 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 815 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 815 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 816 // Returns the last argument in R0. | 816 // Returns the last argument in R0. |
| 817 static void TestLastArgumentIsDouble(Assembler* assembler, | 817 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 818 Label* is_smi, | 818 Label* is_smi, |
| 819 Label* not_double_smi) { | 819 Label* not_double_smi) { |
| 820 __ ldr(R0, Address(SP, 0 * kWordSize)); | 820 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 821 __ tsti(R0, kSmiTagMask); | 821 __ tsti(R0, Immediate(kSmiTagMask)); |
| 822 __ b(is_smi, EQ); | 822 __ b(is_smi, EQ); |
| 823 __ CompareClassId(R0, kDoubleCid, kNoPP); | 823 __ CompareClassId(R0, kDoubleCid, kNoPP); |
| 824 __ b(not_double_smi, NE); | 824 __ b(not_double_smi, NE); |
| 825 // Fall through with Double in R0. | 825 // Fall through with Double in R0. |
| 826 } | 826 } |
| 827 | 827 |
| 828 | 828 |
| 829 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 829 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
| 830 // type. Return true or false object in the register R0. Any NaN argument | 830 // type. Return true or false object in the register R0. Any NaN argument |
| 831 // returns false. Any non-double arg1 causes control flow to fall through to the | 831 // 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... |
| 928 void Intrinsifier::Double_div(Assembler* assembler) { | 928 void Intrinsifier::Double_div(Assembler* assembler) { |
| 929 DoubleArithmeticOperations(assembler, Token::kDIV); | 929 DoubleArithmeticOperations(assembler, Token::kDIV); |
| 930 } | 930 } |
| 931 | 931 |
| 932 | 932 |
| 933 // Left is double right is integer (Bigint, Mint or Smi) | 933 // Left is double right is integer (Bigint, Mint or Smi) |
| 934 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 934 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 935 Label fall_through; | 935 Label fall_through; |
| 936 // Only smis allowed. | 936 // Only smis allowed. |
| 937 __ ldr(R0, Address(SP, 0 * kWordSize)); | 937 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 938 __ tsti(R0, kSmiTagMask); | 938 __ tsti(R0, Immediate(kSmiTagMask)); |
| 939 __ b(&fall_through, NE); | 939 __ b(&fall_through, NE); |
| 940 // Is Smi. | 940 // Is Smi. |
| 941 __ SmiUntag(R0); | 941 __ SmiUntag(R0); |
| 942 __ scvtfd(V1, R0); | 942 __ scvtfd(V1, R0); |
| 943 __ ldr(R0, Address(SP, 1 * kWordSize)); | 943 __ ldr(R0, Address(SP, 1 * kWordSize)); |
| 944 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); | 944 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); |
| 945 __ fmuld(V0, V0, V1); | 945 __ fmuld(V0, V0, V1); |
| 946 const Class& double_class = Class::Handle( | 946 const Class& double_class = Class::Handle( |
| 947 Isolate::Current()->object_store()->double_class()); | 947 Isolate::Current()->object_store()->double_class()); |
| 948 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); | 948 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); |
| 949 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); | 949 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); |
| 950 __ ret(); | 950 __ ret(); |
| 951 __ Bind(&fall_through); | 951 __ Bind(&fall_through); |
| 952 } | 952 } |
| 953 | 953 |
| 954 | 954 |
| 955 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { | 955 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { |
| 956 Label fall_through; | 956 Label fall_through; |
| 957 | 957 |
| 958 __ ldr(R0, Address(SP, 0 * kWordSize)); | 958 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 959 __ tsti(R0, kSmiTagMask); | 959 __ tsti(R0, Immediate(kSmiTagMask)); |
| 960 __ b(&fall_through, NE); | 960 __ b(&fall_through, NE); |
| 961 // Is Smi. | 961 // Is Smi. |
| 962 __ SmiUntag(R0); | 962 __ SmiUntag(R0); |
| 963 __ scvtfd(V0, R0); | 963 __ scvtfd(V0, R0); |
| 964 const Class& double_class = Class::Handle( | 964 const Class& double_class = Class::Handle( |
| 965 Isolate::Current()->object_store()->double_class()); | 965 Isolate::Current()->object_store()->double_class()); |
| 966 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); | 966 __ TryAllocate(double_class, &fall_through, R0, R1, kNoPP); |
| 967 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); | 967 __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP); |
| 968 __ ret(); | 968 __ ret(); |
| 969 __ Bind(&fall_through); | 969 __ Bind(&fall_through); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 999 __ Bind(&is_true); | 999 __ Bind(&is_true); |
| 1000 __ mov(R0, true_reg); | 1000 __ mov(R0, true_reg); |
| 1001 | 1001 |
| 1002 __ Bind(&is_false); | 1002 __ Bind(&is_false); |
| 1003 __ ret(); | 1003 __ ret(); |
| 1004 | 1004 |
| 1005 __ Bind(&is_zero); | 1005 __ Bind(&is_zero); |
| 1006 // Check for negative zero by looking at the sign bit. | 1006 // Check for negative zero by looking at the sign bit. |
| 1007 __ fmovrd(R1, V0); | 1007 __ fmovrd(R1, V0); |
| 1008 __ LsrImmediate(R1, R1, 63); | 1008 __ LsrImmediate(R1, R1, 63); |
| 1009 __ tsti(R1, 1); | 1009 __ tsti(R1, Immediate(1)); |
| 1010 __ csel(R0, true_reg, false_reg, NE); // Sign bit set. | 1010 __ csel(R0, true_reg, false_reg, NE); // Sign bit set. |
| 1011 __ ret(); | 1011 __ ret(); |
| 1012 } | 1012 } |
| 1013 | 1013 |
| 1014 | 1014 |
| 1015 void Intrinsifier::DoubleToInteger(Assembler* assembler) { | 1015 void Intrinsifier::DoubleToInteger(Assembler* assembler) { |
| 1016 Label fall_through; | 1016 Label fall_through; |
| 1017 | 1017 |
| 1018 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1018 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1019 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); | 1019 __ LoadDFieldFromOffset(V0, R0, Double::value_offset(), kNoPP); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver. | 1076 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver. |
| 1077 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'. | 1077 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'. |
| 1078 | 1078 |
| 1079 // Addresses of _state[0]. | 1079 // Addresses of _state[0]. |
| 1080 const int64_t disp = | 1080 const int64_t disp = |
| 1081 Instance::DataOffsetFor(kTypedDataUint32ArrayCid) - kHeapObjectTag; | 1081 Instance::DataOffsetFor(kTypedDataUint32ArrayCid) - kHeapObjectTag; |
| 1082 | 1082 |
| 1083 __ LoadImmediate(R0, a_int_value, kNoPP); | 1083 __ LoadImmediate(R0, a_int_value, kNoPP); |
| 1084 __ LoadFromOffset(R2, R1, disp, kNoPP); | 1084 __ LoadFromOffset(R2, R1, disp, kNoPP); |
| 1085 __ LsrImmediate(R3, R2, 32); | 1085 __ LsrImmediate(R3, R2, 32); |
| 1086 __ andi(R2, R2, 0xffffffff); | 1086 __ andi(R2, R2, Immediate(0xffffffff)); |
| 1087 __ mul(R2, R0, R2); | 1087 __ mul(R2, R0, R2); |
| 1088 __ add(R2, R2, Operand(R3)); | 1088 __ add(R2, R2, Operand(R3)); |
| 1089 __ StoreToOffset(R2, R1, disp, kNoPP); | 1089 __ StoreToOffset(R2, R1, disp, kNoPP); |
| 1090 __ ret(); | 1090 __ ret(); |
| 1091 } | 1091 } |
| 1092 | 1092 |
| 1093 | 1093 |
| 1094 void Intrinsifier::ObjectEquals(Assembler* assembler) { | 1094 void Intrinsifier::ObjectEquals(Assembler* assembler) { |
| 1095 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1095 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1096 __ ldr(R1, Address(SP, 1 * kWordSize)); | 1096 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1112 // Hash not yet computed. | 1112 // Hash not yet computed. |
| 1113 __ Bind(&fall_through); | 1113 __ Bind(&fall_through); |
| 1114 } | 1114 } |
| 1115 | 1115 |
| 1116 | 1116 |
| 1117 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { | 1117 void Intrinsifier::StringBaseCodeUnitAt(Assembler* assembler) { |
| 1118 Label fall_through, try_two_byte_string; | 1118 Label fall_through, try_two_byte_string; |
| 1119 | 1119 |
| 1120 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1120 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1121 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1121 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1122 __ tsti(R1, kSmiTagMask); | 1122 __ tsti(R1, Immediate(kSmiTagMask)); |
| 1123 __ b(&fall_through, NE); // Index is not a Smi. | 1123 __ b(&fall_through, NE); // Index is not a Smi. |
| 1124 // Range check. | 1124 // Range check. |
| 1125 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1125 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1126 __ cmp(R1, Operand(R2)); | 1126 __ cmp(R1, Operand(R2)); |
| 1127 __ b(&fall_through, CS); // Runtime throws exception. | 1127 __ b(&fall_through, CS); // Runtime throws exception. |
| 1128 __ CompareClassId(R0, kOneByteStringCid, kNoPP); | 1128 __ CompareClassId(R0, kOneByteStringCid, kNoPP); |
| 1129 __ b(&try_two_byte_string, NE); | 1129 __ b(&try_two_byte_string, NE); |
| 1130 __ SmiUntag(R1); | 1130 __ SmiUntag(R1); |
| 1131 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); | 1131 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); |
| 1132 __ ldr(R0, Address(R0, R1), kUnsignedByte); | 1132 __ ldr(R0, Address(R0, R1), kUnsignedByte); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1144 | 1144 |
| 1145 __ Bind(&fall_through); | 1145 __ Bind(&fall_through); |
| 1146 } | 1146 } |
| 1147 | 1147 |
| 1148 | 1148 |
| 1149 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { | 1149 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { |
| 1150 Label fall_through, try_two_byte_string; | 1150 Label fall_through, try_two_byte_string; |
| 1151 | 1151 |
| 1152 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. | 1152 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. |
| 1153 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. | 1153 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. |
| 1154 __ tsti(R1, kSmiTagMask); | 1154 __ tsti(R1, Immediate(kSmiTagMask)); |
| 1155 __ b(&fall_through, NE); // Index is not a Smi. | 1155 __ b(&fall_through, NE); // Index is not a Smi. |
| 1156 // Range check. | 1156 // Range check. |
| 1157 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1157 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1158 __ cmp(R1, Operand(R2)); | 1158 __ cmp(R1, Operand(R2)); |
| 1159 __ b(&fall_through, CS); // Runtime throws exception. | 1159 __ b(&fall_through, CS); // Runtime throws exception. |
| 1160 | 1160 |
| 1161 __ CompareClassId(R0, kOneByteStringCid, kNoPP); | 1161 __ CompareClassId(R0, kOneByteStringCid, kNoPP); |
| 1162 __ b(&try_two_byte_string, NE); | 1162 __ b(&try_two_byte_string, NE); |
| 1163 __ SmiUntag(R1); | 1163 __ SmiUntag(R1); |
| 1164 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); | 1164 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag, kNoPP); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1270 static void TryAllocateOnebyteString(Assembler* assembler, | 1270 static void TryAllocateOnebyteString(Assembler* assembler, |
| 1271 Label* ok, | 1271 Label* ok, |
| 1272 Label* failure) { | 1272 Label* failure) { |
| 1273 const Register length_reg = R2; | 1273 const Register length_reg = R2; |
| 1274 Label fail; | 1274 Label fail; |
| 1275 | 1275 |
| 1276 __ mov(R6, length_reg); // Save the length register. | 1276 __ mov(R6, length_reg); // Save the length register. |
| 1277 __ SmiUntag(length_reg); | 1277 __ SmiUntag(length_reg); |
| 1278 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; | 1278 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; |
| 1279 __ AddImmediate(length_reg, length_reg, fixed_size, kNoPP); | 1279 __ AddImmediate(length_reg, length_reg, fixed_size, kNoPP); |
| 1280 __ andi(length_reg, length_reg, ~(kObjectAlignment - 1)); | 1280 __ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1))); |
| 1281 | 1281 |
| 1282 Isolate* isolate = Isolate::Current(); | 1282 Isolate* isolate = Isolate::Current(); |
| 1283 Heap* heap = isolate->heap(); | 1283 Heap* heap = isolate->heap(); |
| 1284 const intptr_t cid = kOneByteStringCid; | 1284 const intptr_t cid = kOneByteStringCid; |
| 1285 Heap::Space space = heap->SpaceForAllocation(cid); | 1285 Heap::Space space = heap->SpaceForAllocation(cid); |
| 1286 __ LoadImmediate(R3, heap->TopAddress(space), kNoPP); | 1286 __ LoadImmediate(R3, heap->TopAddress(space), kNoPP); |
| 1287 __ ldr(R0, Address(R3)); | 1287 __ ldr(R0, Address(R3)); |
| 1288 | 1288 |
| 1289 // length_reg: allocation size. | 1289 // length_reg: allocation size. |
| 1290 __ adds(R1, R0, Operand(length_reg)); | 1290 __ adds(R1, R0, Operand(length_reg)); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 // The indexes must be valid. | 1344 // The indexes must be valid. |
| 1345 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 1345 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
| 1346 const intptr_t kStringOffset = 2 * kWordSize; | 1346 const intptr_t kStringOffset = 2 * kWordSize; |
| 1347 const intptr_t kStartIndexOffset = 1 * kWordSize; | 1347 const intptr_t kStartIndexOffset = 1 * kWordSize; |
| 1348 const intptr_t kEndIndexOffset = 0 * kWordSize; | 1348 const intptr_t kEndIndexOffset = 0 * kWordSize; |
| 1349 Label fall_through, ok; | 1349 Label fall_through, ok; |
| 1350 | 1350 |
| 1351 __ ldr(R2, Address(SP, kEndIndexOffset)); | 1351 __ ldr(R2, Address(SP, kEndIndexOffset)); |
| 1352 __ ldr(TMP, Address(SP, kStartIndexOffset)); | 1352 __ ldr(TMP, Address(SP, kStartIndexOffset)); |
| 1353 __ orr(R3, R2, Operand(TMP)); | 1353 __ orr(R3, R2, Operand(TMP)); |
| 1354 __ tsti(R3, kSmiTagMask); | 1354 __ tsti(R3, Immediate(kSmiTagMask)); |
| 1355 __ b(&fall_through, NE); // 'start', 'end' not Smi. | 1355 __ b(&fall_through, NE); // 'start', 'end' not Smi. |
| 1356 | 1356 |
| 1357 __ sub(R2, R2, Operand(TMP)); | 1357 __ sub(R2, R2, Operand(TMP)); |
| 1358 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 1358 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 1359 __ Bind(&ok); | 1359 __ Bind(&ok); |
| 1360 // R0: new string as tagged pointer. | 1360 // R0: new string as tagged pointer. |
| 1361 // Copy string. | 1361 // Copy string. |
| 1362 __ ldr(R3, Address(SP, kStringOffset)); | 1362 __ ldr(R3, Address(SP, kStringOffset)); |
| 1363 __ ldr(R1, Address(SP, kStartIndexOffset)); | 1363 __ ldr(R1, Address(SP, kStartIndexOffset)); |
| 1364 __ SmiUntag(R1); | 1364 __ SmiUntag(R1); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1427 void StringEquality(Assembler* assembler, intptr_t string_cid) { | 1427 void StringEquality(Assembler* assembler, intptr_t string_cid) { |
| 1428 Label fall_through, is_true, is_false, loop; | 1428 Label fall_through, is_true, is_false, loop; |
| 1429 __ ldr(R0, Address(SP, 1 * kWordSize)); // This. | 1429 __ ldr(R0, Address(SP, 1 * kWordSize)); // This. |
| 1430 __ ldr(R1, Address(SP, 0 * kWordSize)); // Other. | 1430 __ ldr(R1, Address(SP, 0 * kWordSize)); // Other. |
| 1431 | 1431 |
| 1432 // Are identical? | 1432 // Are identical? |
| 1433 __ cmp(R0, Operand(R1)); | 1433 __ cmp(R0, Operand(R1)); |
| 1434 __ b(&is_true, EQ); | 1434 __ b(&is_true, EQ); |
| 1435 | 1435 |
| 1436 // Is other OneByteString? | 1436 // Is other OneByteString? |
| 1437 __ tsti(R1, kSmiTagMask); | 1437 __ tsti(R1, Immediate(kSmiTagMask)); |
| 1438 __ b(&fall_through, EQ); | 1438 __ b(&fall_through, EQ); |
| 1439 __ CompareClassId(R1, string_cid, kNoPP); | 1439 __ CompareClassId(R1, string_cid, kNoPP); |
| 1440 __ b(&fall_through, NE); | 1440 __ b(&fall_through, NE); |
| 1441 | 1441 |
| 1442 // Have same length? | 1442 // Have same length? |
| 1443 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1443 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1444 __ ldr(R3, FieldAddress(R1, String::length_offset())); | 1444 __ ldr(R3, FieldAddress(R1, String::length_offset())); |
| 1445 __ cmp(R2, Operand(R3)); | 1445 __ cmp(R2, Operand(R3)); |
| 1446 __ b(&is_false, NE); | 1446 __ b(&is_false, NE); |
| 1447 | 1447 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1532 Isolate* isolate = Isolate::Current(); | 1532 Isolate* isolate = Isolate::Current(); |
| 1533 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); | 1533 __ LoadImmediate(R1, reinterpret_cast<uword>(isolate), kNoPP); |
| 1534 // Set return value to Isolate::current_tag_. | 1534 // Set return value to Isolate::current_tag_. |
| 1535 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); | 1535 __ ldr(R0, Address(R1, Isolate::current_tag_offset())); |
| 1536 __ ret(); | 1536 __ ret(); |
| 1537 } | 1537 } |
| 1538 | 1538 |
| 1539 } // namespace dart | 1539 } // namespace dart |
| 1540 | 1540 |
| 1541 #endif // defined TARGET_ARCH_ARM64 | 1541 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |