| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 // This snippet of inlined code uses the following registers: | 65 // This snippet of inlined code uses the following registers: |
| 66 // RAX, RCX, R13 | 66 // RAX, RCX, R13 |
| 67 // and the newly allocated object is returned in RAX. | 67 // and the newly allocated object is returned in RAX. |
| 68 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 68 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 69 const intptr_t kArrayOffset = 1 * kWordSize; | 69 const intptr_t kArrayOffset = 1 * kWordSize; |
| 70 Label fall_through; | 70 Label fall_through; |
| 71 | 71 |
| 72 // Try allocating in new space. | 72 // Try allocating in new space. |
| 73 const Class& cls = Class::Handle( | 73 const Class& cls = Class::Handle( |
| 74 Isolate::Current()->object_store()->growable_object_array_class()); | 74 Isolate::Current()->object_store()->growable_object_array_class()); |
| 75 __ TryAllocate(cls, &fall_through, Assembler::kFarJump, RAX, kNoRegister); | 75 __ TryAllocate(cls, &fall_through, Assembler::kFarJump, RAX); |
| 76 | 76 |
| 77 // Store backing array object in growable array object. | 77 // Store backing array object in growable array object. |
| 78 __ movq(RCX, Address(RSP, kArrayOffset)); // data argument. | 78 __ movq(RCX, Address(RSP, kArrayOffset)); // data argument. |
| 79 // RAX is new, no barrier needed. | 79 // RAX is new, no barrier needed. |
| 80 __ InitializeFieldNoBarrier( | 80 __ InitializeFieldNoBarrier( |
| 81 RAX, | 81 RAX, |
| 82 FieldAddress(RAX, GrowableObjectArray::data_offset()), | 82 FieldAddress(RAX, GrowableObjectArray::data_offset()), |
| 83 RCX); | 83 RCX); |
| 84 | 84 |
| 85 // RAX: new growable array object start as a tagged pointer. | 85 // RAX: new growable array object start as a tagged pointer. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 114 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); | 114 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); |
| 115 __ j(EQUAL, &fall_through); // Must grow data. | 115 __ j(EQUAL, &fall_through); // Must grow data. |
| 116 // len = len + 1; | 116 // len = len + 1; |
| 117 __ IncrementSmiField(FieldAddress(RAX, GrowableObjectArray::length_offset()), | 117 __ IncrementSmiField(FieldAddress(RAX, GrowableObjectArray::length_offset()), |
| 118 1); | 118 1); |
| 119 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Value | 119 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Value |
| 120 ASSERT(kSmiTagShift == 1); | 120 ASSERT(kSmiTagShift == 1); |
| 121 __ StoreIntoObject(RDX, | 121 __ StoreIntoObject(RDX, |
| 122 FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()), | 122 FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()), |
| 123 RAX); | 123 RAX); |
| 124 __ LoadObject(RAX, Object::null_object(), PP); | 124 __ LoadObject(RAX, Object::null_object()); |
| 125 __ ret(); | 125 __ ret(); |
| 126 __ Bind(&fall_through); | 126 __ Bind(&fall_through); |
| 127 } | 127 } |
| 128 | 128 |
| 129 | 129 |
| 130 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ | 130 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ |
| 131 Label fall_through; \ | 131 Label fall_through; \ |
| 132 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ | 132 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ |
| 133 __ MaybeTraceAllocation(cid, &fall_through, false); \ | 133 __ MaybeTraceAllocation(cid, &fall_through, false); \ |
| 134 __ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \ | 134 __ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \ |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 __ Bind(&fall_through); | 576 __ Bind(&fall_through); |
| 577 } | 577 } |
| 578 | 578 |
| 579 | 579 |
| 580 static void CompareIntegers(Assembler* assembler, Condition true_condition) { | 580 static void CompareIntegers(Assembler* assembler, Condition true_condition) { |
| 581 Label fall_through, true_label; | 581 Label fall_through, true_label; |
| 582 TestBothArgumentsSmis(assembler, &fall_through); | 582 TestBothArgumentsSmis(assembler, &fall_through); |
| 583 // RAX contains the right argument. | 583 // RAX contains the right argument. |
| 584 __ cmpq(Address(RSP, + 2 * kWordSize), RAX); | 584 __ cmpq(Address(RSP, + 2 * kWordSize), RAX); |
| 585 __ j(true_condition, &true_label, Assembler::kNearJump); | 585 __ j(true_condition, &true_label, Assembler::kNearJump); |
| 586 __ LoadObject(RAX, Bool::False(), PP); | 586 __ LoadObject(RAX, Bool::False()); |
| 587 __ ret(); | 587 __ ret(); |
| 588 __ Bind(&true_label); | 588 __ Bind(&true_label); |
| 589 __ LoadObject(RAX, Bool::True(), PP); | 589 __ LoadObject(RAX, Bool::True()); |
| 590 __ ret(); | 590 __ ret(); |
| 591 __ Bind(&fall_through); | 591 __ Bind(&fall_through); |
| 592 } | 592 } |
| 593 | 593 |
| 594 | 594 |
| 595 void Intrinsifier::Integer_lessThan(Assembler* assembler) { | 595 void Intrinsifier::Integer_lessThan(Assembler* assembler) { |
| 596 CompareIntegers(assembler, LESS); | 596 CompareIntegers(assembler, LESS); |
| 597 } | 597 } |
| 598 | 598 |
| 599 | 599 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 626 | 626 |
| 627 // For integer receiver '===' check first. | 627 // For integer receiver '===' check first. |
| 628 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); | 628 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); |
| 629 __ movq(RCX, Address(RSP, + kReceiverOffset * kWordSize)); | 629 __ movq(RCX, Address(RSP, + kReceiverOffset * kWordSize)); |
| 630 __ cmpq(RAX, RCX); | 630 __ cmpq(RAX, RCX); |
| 631 __ j(EQUAL, &true_label, Assembler::kNearJump); | 631 __ j(EQUAL, &true_label, Assembler::kNearJump); |
| 632 __ orq(RAX, RCX); | 632 __ orq(RAX, RCX); |
| 633 __ testq(RAX, Immediate(kSmiTagMask)); | 633 __ testq(RAX, Immediate(kSmiTagMask)); |
| 634 __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump); | 634 __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump); |
| 635 // Both arguments are smi, '===' is good enough. | 635 // Both arguments are smi, '===' is good enough. |
| 636 __ LoadObject(RAX, Bool::False(), PP); | 636 __ LoadObject(RAX, Bool::False()); |
| 637 __ ret(); | 637 __ ret(); |
| 638 __ Bind(&true_label); | 638 __ Bind(&true_label); |
| 639 __ LoadObject(RAX, Bool::True(), PP); | 639 __ LoadObject(RAX, Bool::True()); |
| 640 __ ret(); | 640 __ ret(); |
| 641 | 641 |
| 642 // At least one of the arguments was not Smi. | 642 // At least one of the arguments was not Smi. |
| 643 Label receiver_not_smi; | 643 Label receiver_not_smi; |
| 644 __ Bind(&check_for_mint); | 644 __ Bind(&check_for_mint); |
| 645 __ movq(RAX, Address(RSP, + kReceiverOffset * kWordSize)); | 645 __ movq(RAX, Address(RSP, + kReceiverOffset * kWordSize)); |
| 646 __ testq(RAX, Immediate(kSmiTagMask)); | 646 __ testq(RAX, Immediate(kSmiTagMask)); |
| 647 __ j(NOT_ZERO, &receiver_not_smi); | 647 __ j(NOT_ZERO, &receiver_not_smi); |
| 648 | 648 |
| 649 // Left (receiver) is Smi, return false if right is not Double. | 649 // Left (receiver) is Smi, return false if right is not Double. |
| 650 // Note that an instance of Mint or Bigint never contains a value that can be | 650 // Note that an instance of Mint or Bigint never contains a value that can be |
| 651 // represented by Smi. | 651 // represented by Smi. |
| 652 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); | 652 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); |
| 653 __ CompareClassId(RAX, kDoubleCid); | 653 __ CompareClassId(RAX, kDoubleCid); |
| 654 __ j(EQUAL, &fall_through); | 654 __ j(EQUAL, &fall_through); |
| 655 __ LoadObject(RAX, Bool::False(), PP); | 655 __ LoadObject(RAX, Bool::False()); |
| 656 __ ret(); | 656 __ ret(); |
| 657 | 657 |
| 658 __ Bind(&receiver_not_smi); | 658 __ Bind(&receiver_not_smi); |
| 659 // RAX:: receiver. | 659 // RAX:: receiver. |
| 660 __ CompareClassId(RAX, kMintCid); | 660 __ CompareClassId(RAX, kMintCid); |
| 661 __ j(NOT_EQUAL, &fall_through); | 661 __ j(NOT_EQUAL, &fall_through); |
| 662 // Receiver is Mint, return false if right is Smi. | 662 // Receiver is Mint, return false if right is Smi. |
| 663 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); | 663 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); |
| 664 __ testq(RAX, Immediate(kSmiTagMask)); | 664 __ testq(RAX, Immediate(kSmiTagMask)); |
| 665 __ j(NOT_ZERO, &fall_through); | 665 __ j(NOT_ZERO, &fall_through); |
| 666 // Smi == Mint -> false. | 666 // Smi == Mint -> false. |
| 667 __ LoadObject(RAX, Bool::False(), PP); | 667 __ LoadObject(RAX, Bool::False()); |
| 668 __ ret(); | 668 __ ret(); |
| 669 // TODO(srdjan): Implement Mint == Mint comparison. | 669 // TODO(srdjan): Implement Mint == Mint comparison. |
| 670 | 670 |
| 671 __ Bind(&fall_through); | 671 __ Bind(&fall_through); |
| 672 } | 672 } |
| 673 | 673 |
| 674 | 674 |
| 675 void Intrinsifier::Integer_equal(Assembler* assembler) { | 675 void Intrinsifier::Integer_equal(Assembler* assembler) { |
| 676 Integer_equalToInteger(assembler); | 676 Integer_equalToInteger(assembler); |
| 677 } | 677 } |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1255 // Both arguments are double, right operand is in RAX. | 1255 // Both arguments are double, right operand is in RAX. |
| 1256 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1256 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
| 1257 __ Bind(&double_op); | 1257 __ Bind(&double_op); |
| 1258 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument. | 1258 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument. |
| 1259 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1259 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1260 __ comisd(XMM0, XMM1); | 1260 __ comisd(XMM0, XMM1); |
| 1261 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | 1261 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; |
| 1262 __ j(true_condition, &is_true, Assembler::kNearJump); | 1262 __ j(true_condition, &is_true, Assembler::kNearJump); |
| 1263 // Fall through false. | 1263 // Fall through false. |
| 1264 __ Bind(&is_false); | 1264 __ Bind(&is_false); |
| 1265 __ LoadObject(RAX, Bool::False(), PP); | 1265 __ LoadObject(RAX, Bool::False()); |
| 1266 __ ret(); | 1266 __ ret(); |
| 1267 __ Bind(&is_true); | 1267 __ Bind(&is_true); |
| 1268 __ LoadObject(RAX, Bool::True(), PP); | 1268 __ LoadObject(RAX, Bool::True()); |
| 1269 __ ret(); | 1269 __ ret(); |
| 1270 __ Bind(&is_smi); | 1270 __ Bind(&is_smi); |
| 1271 __ SmiUntag(RAX); | 1271 __ SmiUntag(RAX); |
| 1272 __ cvtsi2sdq(XMM1, RAX); | 1272 __ cvtsi2sdq(XMM1, RAX); |
| 1273 __ jmp(&double_op); | 1273 __ jmp(&double_op); |
| 1274 __ Bind(&fall_through); | 1274 __ Bind(&fall_through); |
| 1275 } | 1275 } |
| 1276 | 1276 |
| 1277 | 1277 |
| 1278 void Intrinsifier::Double_greaterThan(Assembler* assembler) { | 1278 void Intrinsifier::Double_greaterThan(Assembler* assembler) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 case Token::kSUB: __ subsd(XMM0, XMM1); break; | 1314 case Token::kSUB: __ subsd(XMM0, XMM1); break; |
| 1315 case Token::kMUL: __ mulsd(XMM0, XMM1); break; | 1315 case Token::kMUL: __ mulsd(XMM0, XMM1); break; |
| 1316 case Token::kDIV: __ divsd(XMM0, XMM1); break; | 1316 case Token::kDIV: __ divsd(XMM0, XMM1); break; |
| 1317 default: UNREACHABLE(); | 1317 default: UNREACHABLE(); |
| 1318 } | 1318 } |
| 1319 const Class& double_class = Class::Handle( | 1319 const Class& double_class = Class::Handle( |
| 1320 Isolate::Current()->object_store()->double_class()); | 1320 Isolate::Current()->object_store()->double_class()); |
| 1321 __ TryAllocate(double_class, | 1321 __ TryAllocate(double_class, |
| 1322 &fall_through, | 1322 &fall_through, |
| 1323 Assembler::kFarJump, | 1323 Assembler::kFarJump, |
| 1324 RAX, // Result register. | 1324 RAX); // Result register. |
| 1325 kNoRegister); // Pool pointer might not be loaded. | |
| 1326 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1325 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1327 __ ret(); | 1326 __ ret(); |
| 1328 __ Bind(&fall_through); | 1327 __ Bind(&fall_through); |
| 1329 } | 1328 } |
| 1330 | 1329 |
| 1331 | 1330 |
| 1332 void Intrinsifier::Double_add(Assembler* assembler) { | 1331 void Intrinsifier::Double_add(Assembler* assembler) { |
| 1333 DoubleArithmeticOperations(assembler, Token::kADD); | 1332 DoubleArithmeticOperations(assembler, Token::kADD); |
| 1334 } | 1333 } |
| 1335 | 1334 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1359 __ SmiUntag(RAX); | 1358 __ SmiUntag(RAX); |
| 1360 __ cvtsi2sdq(XMM1, RAX); | 1359 __ cvtsi2sdq(XMM1, RAX); |
| 1361 __ movq(RAX, Address(RSP, + 2 * kWordSize)); | 1360 __ movq(RAX, Address(RSP, + 2 * kWordSize)); |
| 1362 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1361 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1363 __ mulsd(XMM0, XMM1); | 1362 __ mulsd(XMM0, XMM1); |
| 1364 const Class& double_class = Class::Handle( | 1363 const Class& double_class = Class::Handle( |
| 1365 Isolate::Current()->object_store()->double_class()); | 1364 Isolate::Current()->object_store()->double_class()); |
| 1366 __ TryAllocate(double_class, | 1365 __ TryAllocate(double_class, |
| 1367 &fall_through, | 1366 &fall_through, |
| 1368 Assembler::kFarJump, | 1367 Assembler::kFarJump, |
| 1369 RAX, // Result register. | 1368 RAX); // Result register. |
| 1370 kNoRegister); // Pool pointer might not be loaded. | |
| 1371 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1369 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1372 __ ret(); | 1370 __ ret(); |
| 1373 __ Bind(&fall_through); | 1371 __ Bind(&fall_through); |
| 1374 } | 1372 } |
| 1375 | 1373 |
| 1376 | 1374 |
| 1377 // Left is double right is integer (Bigint, Mint or Smi) | 1375 // Left is double right is integer (Bigint, Mint or Smi) |
| 1378 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { | 1376 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { |
| 1379 Label fall_through; | 1377 Label fall_through; |
| 1380 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1378 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
| 1381 __ testq(RAX, Immediate(kSmiTagMask)); | 1379 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1382 __ j(NOT_ZERO, &fall_through); | 1380 __ j(NOT_ZERO, &fall_through); |
| 1383 // Is Smi. | 1381 // Is Smi. |
| 1384 __ SmiUntag(RAX); | 1382 __ SmiUntag(RAX); |
| 1385 __ cvtsi2sdq(XMM0, RAX); | 1383 __ cvtsi2sdq(XMM0, RAX); |
| 1386 const Class& double_class = Class::Handle( | 1384 const Class& double_class = Class::Handle( |
| 1387 Isolate::Current()->object_store()->double_class()); | 1385 Isolate::Current()->object_store()->double_class()); |
| 1388 __ TryAllocate(double_class, | 1386 __ TryAllocate(double_class, |
| 1389 &fall_through, | 1387 &fall_through, |
| 1390 Assembler::kFarJump, | 1388 Assembler::kFarJump, |
| 1391 RAX, // Result register. | 1389 RAX); // Result register. |
| 1392 kNoRegister); // Pool pointer might not be loaded. | |
| 1393 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1390 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1394 __ ret(); | 1391 __ ret(); |
| 1395 __ Bind(&fall_through); | 1392 __ Bind(&fall_through); |
| 1396 } | 1393 } |
| 1397 | 1394 |
| 1398 | 1395 |
| 1399 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1396 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
| 1400 Label is_true; | 1397 Label is_true; |
| 1401 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1398 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
| 1402 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1399 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1403 __ comisd(XMM0, XMM0); | 1400 __ comisd(XMM0, XMM0); |
| 1404 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; | 1401 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; |
| 1405 __ LoadObject(RAX, Bool::False(), PP); | 1402 __ LoadObject(RAX, Bool::False()); |
| 1406 __ ret(); | 1403 __ ret(); |
| 1407 __ Bind(&is_true); | 1404 __ Bind(&is_true); |
| 1408 __ LoadObject(RAX, Bool::True(), PP); | 1405 __ LoadObject(RAX, Bool::True()); |
| 1409 __ ret(); | 1406 __ ret(); |
| 1410 } | 1407 } |
| 1411 | 1408 |
| 1412 | 1409 |
| 1413 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1410 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
| 1414 Label is_false, is_true, is_zero; | 1411 Label is_false, is_true, is_zero; |
| 1415 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1412 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
| 1416 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1413 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1417 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. | 1414 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. |
| 1418 __ comisd(XMM0, XMM1); | 1415 __ comisd(XMM0, XMM1); |
| 1419 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. | 1416 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. |
| 1420 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. | 1417 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. |
| 1421 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. | 1418 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. |
| 1422 __ Bind(&is_true); | 1419 __ Bind(&is_true); |
| 1423 __ LoadObject(RAX, Bool::True(), PP); | 1420 __ LoadObject(RAX, Bool::True()); |
| 1424 __ ret(); | 1421 __ ret(); |
| 1425 __ Bind(&is_false); | 1422 __ Bind(&is_false); |
| 1426 __ LoadObject(RAX, Bool::False(), PP); | 1423 __ LoadObject(RAX, Bool::False()); |
| 1427 __ ret(); | 1424 __ ret(); |
| 1428 __ Bind(&is_zero); | 1425 __ Bind(&is_zero); |
| 1429 // Check for negative zero (get the sign bit). | 1426 // Check for negative zero (get the sign bit). |
| 1430 __ movmskpd(RAX, XMM0); | 1427 __ movmskpd(RAX, XMM0); |
| 1431 __ testq(RAX, Immediate(1)); | 1428 __ testq(RAX, Immediate(1)); |
| 1432 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); | 1429 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); |
| 1433 __ jmp(&is_false, Assembler::kNearJump); | 1430 __ jmp(&is_false, Assembler::kNearJump); |
| 1434 } | 1431 } |
| 1435 | 1432 |
| 1436 | 1433 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1455 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1452 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1456 // Argument is double and is in RAX. | 1453 // Argument is double and is in RAX. |
| 1457 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1454 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
| 1458 __ Bind(&double_op); | 1455 __ Bind(&double_op); |
| 1459 __ sqrtsd(XMM0, XMM1); | 1456 __ sqrtsd(XMM0, XMM1); |
| 1460 const Class& double_class = Class::Handle( | 1457 const Class& double_class = Class::Handle( |
| 1461 Isolate::Current()->object_store()->double_class()); | 1458 Isolate::Current()->object_store()->double_class()); |
| 1462 __ TryAllocate(double_class, | 1459 __ TryAllocate(double_class, |
| 1463 &fall_through, | 1460 &fall_through, |
| 1464 Assembler::kFarJump, | 1461 Assembler::kFarJump, |
| 1465 RAX, // Result register. | 1462 RAX); // Result register. |
| 1466 kNoRegister); // Pool pointer might not be loaded. | |
| 1467 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1463 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1468 __ ret(); | 1464 __ ret(); |
| 1469 __ Bind(&is_smi); | 1465 __ Bind(&is_smi); |
| 1470 __ SmiUntag(RAX); | 1466 __ SmiUntag(RAX); |
| 1471 __ cvtsi2sdq(XMM1, RAX); | 1467 __ cvtsi2sdq(XMM1, RAX); |
| 1472 __ jmp(&double_op); | 1468 __ jmp(&double_op); |
| 1473 __ Bind(&fall_through); | 1469 __ Bind(&fall_through); |
| 1474 } | 1470 } |
| 1475 | 1471 |
| 1476 | 1472 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1512 | 1508 |
| 1513 // Identity comparison. | 1509 // Identity comparison. |
| 1514 void Intrinsifier::ObjectEquals(Assembler* assembler) { | 1510 void Intrinsifier::ObjectEquals(Assembler* assembler) { |
| 1515 Label is_true; | 1511 Label is_true; |
| 1516 const intptr_t kReceiverOffset = 2; | 1512 const intptr_t kReceiverOffset = 2; |
| 1517 const intptr_t kArgumentOffset = 1; | 1513 const intptr_t kArgumentOffset = 1; |
| 1518 | 1514 |
| 1519 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); | 1515 __ movq(RAX, Address(RSP, + kArgumentOffset * kWordSize)); |
| 1520 __ cmpq(RAX, Address(RSP, + kReceiverOffset * kWordSize)); | 1516 __ cmpq(RAX, Address(RSP, + kReceiverOffset * kWordSize)); |
| 1521 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1517 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1522 __ LoadObject(RAX, Bool::False(), PP); | 1518 __ LoadObject(RAX, Bool::False()); |
| 1523 __ ret(); | 1519 __ ret(); |
| 1524 __ Bind(&is_true); | 1520 __ Bind(&is_true); |
| 1525 __ LoadObject(RAX, Bool::True(), PP); | 1521 __ LoadObject(RAX, Bool::True()); |
| 1526 __ ret(); | 1522 __ ret(); |
| 1527 } | 1523 } |
| 1528 | 1524 |
| 1529 | 1525 |
| 1530 // Return type quickly for simple types (not parameterized and not signature). | 1526 // Return type quickly for simple types (not parameterized and not signature). |
| 1531 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { | 1527 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { |
| 1532 Label fall_through; | 1528 Label fall_through; |
| 1533 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 1529 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 1534 __ LoadClassIdMayBeSmi(RCX, RAX); | 1530 __ LoadClassIdMayBeSmi(RCX, RAX); |
| 1535 | 1531 |
| 1536 // RCX: untagged cid of instance (RAX). | 1532 // RCX: untagged cid of instance (RAX). |
| 1537 __ LoadClassById(RDI, RCX, PP); | 1533 __ LoadClassById(RDI, RCX); |
| 1538 // RDI: class of instance (RAX). | 1534 // RDI: class of instance (RAX). |
| 1539 __ movq(RCX, FieldAddress(RDI, Class::signature_function_offset())); | 1535 __ movq(RCX, FieldAddress(RDI, Class::signature_function_offset())); |
| 1540 __ CompareObject(RCX, Object::null_object(), PP); | 1536 __ CompareObject(RCX, Object::null_object()); |
| 1541 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1537 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1542 | 1538 |
| 1543 __ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset())); | 1539 __ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset())); |
| 1544 __ cmpq(RCX, Immediate(0)); | 1540 __ cmpq(RCX, Immediate(0)); |
| 1545 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1541 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1546 __ movq(RAX, FieldAddress(RDI, Class::canonical_types_offset())); | 1542 __ movq(RAX, FieldAddress(RDI, Class::canonical_types_offset())); |
| 1547 __ CompareObject(RAX, Object::null_object(), PP); | 1543 __ CompareObject(RAX, Object::null_object()); |
| 1548 __ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set. | 1544 __ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set. |
| 1549 __ ret(); | 1545 __ ret(); |
| 1550 | 1546 |
| 1551 __ Bind(&fall_through); | 1547 __ Bind(&fall_through); |
| 1552 } | 1548 } |
| 1553 | 1549 |
| 1554 | 1550 |
| 1555 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1551 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1556 Label fall_through; | 1552 Label fall_through; |
| 1557 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. | 1553 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1607 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); | 1603 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); |
| 1608 __ SmiUntag(RCX); | 1604 __ SmiUntag(RCX); |
| 1609 __ movzxb(RCX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); | 1605 __ movzxb(RCX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); |
| 1610 __ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); | 1606 __ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); |
| 1611 __ j(GREATER_EQUAL, &fall_through); | 1607 __ j(GREATER_EQUAL, &fall_through); |
| 1612 const ExternalLabel symbols_label( | 1608 const ExternalLabel symbols_label( |
| 1613 reinterpret_cast<uword>(Symbols::PredefinedAddress())); | 1609 reinterpret_cast<uword>(Symbols::PredefinedAddress())); |
| 1614 __ pushq(PP); | 1610 __ pushq(PP); |
| 1615 __ LoadPoolPointer(PP); | 1611 __ LoadPoolPointer(PP); |
| 1616 assembler->set_constant_pool_allowed(true); | 1612 assembler->set_constant_pool_allowed(true); |
| 1617 __ LoadExternalLabel(RAX, &symbols_label, kNotPatchable, PP); | 1613 __ LoadExternalLabel(RAX, &symbols_label, kNotPatchable); |
| 1618 assembler->set_constant_pool_allowed(false); | 1614 assembler->set_constant_pool_allowed(false); |
| 1619 __ popq(PP); | 1615 __ popq(PP); |
| 1620 __ movq(RAX, Address(RAX, | 1616 __ movq(RAX, Address(RAX, |
| 1621 RCX, | 1617 RCX, |
| 1622 TIMES_8, | 1618 TIMES_8, |
| 1623 Symbols::kNullCharCodeSymbolOffset * kWordSize)); | 1619 Symbols::kNullCharCodeSymbolOffset * kWordSize)); |
| 1624 __ ret(); | 1620 __ ret(); |
| 1625 | 1621 |
| 1626 __ Bind(&try_two_byte_string); | 1622 __ Bind(&try_two_byte_string); |
| 1627 __ CompareClassId(RAX, kTwoByteStringCid); | 1623 __ CompareClassId(RAX, kTwoByteStringCid); |
| 1628 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1624 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1629 ASSERT(kSmiTagShift == 1); | 1625 ASSERT(kSmiTagShift == 1); |
| 1630 __ movzxw(RCX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); | 1626 __ movzxw(RCX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); |
| 1631 __ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); | 1627 __ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); |
| 1632 __ j(GREATER_EQUAL, &fall_through); | 1628 __ j(GREATER_EQUAL, &fall_through); |
| 1633 __ pushq(PP); | 1629 __ pushq(PP); |
| 1634 __ LoadPoolPointer(PP); | 1630 __ LoadPoolPointer(PP); |
| 1635 assembler->set_constant_pool_allowed(true); | 1631 assembler->set_constant_pool_allowed(true); |
| 1636 __ LoadExternalLabel(RAX, &symbols_label, kNotPatchable, PP); | 1632 __ LoadExternalLabel(RAX, &symbols_label, kNotPatchable); |
| 1637 assembler->set_constant_pool_allowed(false); | 1633 assembler->set_constant_pool_allowed(false); |
| 1638 __ popq(PP); | 1634 __ popq(PP); |
| 1639 __ movq(RAX, Address(RAX, | 1635 __ movq(RAX, Address(RAX, |
| 1640 RCX, | 1636 RCX, |
| 1641 TIMES_8, | 1637 TIMES_8, |
| 1642 Symbols::kNullCharCodeSymbolOffset * kWordSize)); | 1638 Symbols::kNullCharCodeSymbolOffset * kWordSize)); |
| 1643 __ ret(); | 1639 __ ret(); |
| 1644 | 1640 |
| 1645 __ Bind(&fall_through); | 1641 __ Bind(&fall_through); |
| 1646 } | 1642 } |
| 1647 | 1643 |
| 1648 | 1644 |
| 1649 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { | 1645 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
| 1650 Label is_true; | 1646 Label is_true; |
| 1651 // Get length. | 1647 // Get length. |
| 1652 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. | 1648 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. |
| 1653 __ movq(RAX, FieldAddress(RAX, String::length_offset())); | 1649 __ movq(RAX, FieldAddress(RAX, String::length_offset())); |
| 1654 __ cmpq(RAX, Immediate(Smi::RawValue(0))); | 1650 __ cmpq(RAX, Immediate(Smi::RawValue(0))); |
| 1655 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1651 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1656 __ LoadObject(RAX, Bool::False(), PP); | 1652 __ LoadObject(RAX, Bool::False()); |
| 1657 __ ret(); | 1653 __ ret(); |
| 1658 __ Bind(&is_true); | 1654 __ Bind(&is_true); |
| 1659 __ LoadObject(RAX, Bool::True(), PP); | 1655 __ LoadObject(RAX, Bool::True()); |
| 1660 __ ret(); | 1656 __ ret(); |
| 1661 } | 1657 } |
| 1662 | 1658 |
| 1663 | 1659 |
| 1664 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1660 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
| 1665 Label compute_hash; | 1661 Label compute_hash; |
| 1666 __ movq(RBX, Address(RSP, + 1 * kWordSize)); // OneByteString object. | 1662 __ movq(RBX, Address(RSP, + 1 * kWordSize)); // OneByteString object. |
| 1667 __ movq(RAX, FieldAddress(RBX, String::hash_offset())); | 1663 __ movq(RAX, FieldAddress(RBX, String::hash_offset())); |
| 1668 __ cmpq(RAX, Immediate(0)); | 1664 __ cmpq(RAX, Immediate(0)); |
| 1669 __ j(EQUAL, &compute_hash, Assembler::kNearJump); | 1665 __ j(EQUAL, &compute_hash, Assembler::kNearJump); |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1921 __ movzxw(RDX, | 1917 __ movzxw(RDX, |
| 1922 FieldAddress(RCX, RDI, TIMES_2, TwoByteString::data_offset())); | 1918 FieldAddress(RCX, RDI, TIMES_2, TwoByteString::data_offset())); |
| 1923 } else { | 1919 } else { |
| 1924 UNIMPLEMENTED(); | 1920 UNIMPLEMENTED(); |
| 1925 } | 1921 } |
| 1926 __ cmpq(RBX, RDX); | 1922 __ cmpq(RBX, RDX); |
| 1927 __ j(NOT_EQUAL, &is_false, Assembler::kNearJump); | 1923 __ j(NOT_EQUAL, &is_false, Assembler::kNearJump); |
| 1928 __ jmp(&loop, Assembler::kNearJump); | 1924 __ jmp(&loop, Assembler::kNearJump); |
| 1929 | 1925 |
| 1930 __ Bind(&is_true); | 1926 __ Bind(&is_true); |
| 1931 __ LoadObject(RAX, Bool::True(), PP); | 1927 __ LoadObject(RAX, Bool::True()); |
| 1932 __ ret(); | 1928 __ ret(); |
| 1933 | 1929 |
| 1934 __ Bind(&is_false); | 1930 __ Bind(&is_false); |
| 1935 __ LoadObject(RAX, Bool::False(), PP); | 1931 __ LoadObject(RAX, Bool::False()); |
| 1936 __ ret(); | 1932 __ ret(); |
| 1937 | 1933 |
| 1938 __ Bind(&fall_through); | 1934 __ Bind(&fall_through); |
| 1939 } | 1935 } |
| 1940 | 1936 |
| 1941 | 1937 |
| 1942 void Intrinsifier::OneByteString_equality(Assembler* assembler) { | 1938 void Intrinsifier::OneByteString_equality(Assembler* assembler) { |
| 1943 StringEquality(assembler, kOneByteStringCid); | 1939 StringEquality(assembler, kOneByteStringCid); |
| 1944 } | 1940 } |
| 1945 | 1941 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1959 // Incoming registers: | 1955 // Incoming registers: |
| 1960 // RAX: Function. (Will be loaded with the specialized matcher function.) | 1956 // RAX: Function. (Will be loaded with the specialized matcher function.) |
| 1961 // RCX: Unknown. (Must be GC safe on tail call.) | 1957 // RCX: Unknown. (Must be GC safe on tail call.) |
| 1962 // R10: Arguments descriptor. (Will be preserved.) | 1958 // R10: Arguments descriptor. (Will be preserved.) |
| 1963 | 1959 |
| 1964 // Load the specialized function pointer into RAX. Leverage the fact the | 1960 // Load the specialized function pointer into RAX. Leverage the fact the |
| 1965 // string CIDs as well as stored function pointers are in sequence. | 1961 // string CIDs as well as stored function pointers are in sequence. |
| 1966 __ movq(RBX, Address(RSP, kRegExpParamOffset)); | 1962 __ movq(RBX, Address(RSP, kRegExpParamOffset)); |
| 1967 __ movq(RDI, Address(RSP, kStringParamOffset)); | 1963 __ movq(RDI, Address(RSP, kStringParamOffset)); |
| 1968 __ LoadClassId(RDI, RDI); | 1964 __ LoadClassId(RDI, RDI); |
| 1969 __ SubImmediate(RDI, Immediate(kOneByteStringCid), PP); | 1965 __ SubImmediate(RDI, Immediate(kOneByteStringCid)); |
| 1970 __ movq(RAX, FieldAddress(RBX, RDI, TIMES_8, | 1966 __ movq(RAX, FieldAddress(RBX, RDI, TIMES_8, |
| 1971 JSRegExp::function_offset(kOneByteStringCid))); | 1967 JSRegExp::function_offset(kOneByteStringCid))); |
| 1972 | 1968 |
| 1973 // Registers are now set up for the lazy compile stub. It expects the function | 1969 // Registers are now set up for the lazy compile stub. It expects the function |
| 1974 // in RAX, the argument descriptor in R10, and IC-Data in RCX. | 1970 // in RAX, the argument descriptor in R10, and IC-Data in RCX. |
| 1975 static const intptr_t arg_count = RegExpMacroAssembler::kParamCount; | 1971 static const intptr_t arg_count = RegExpMacroAssembler::kParamCount; |
| 1976 __ LoadObject(R10, | 1972 __ LoadObject(R10, |
| 1977 Array::ZoneHandle(ArgumentsDescriptor::New(arg_count)), PP); | 1973 Array::ZoneHandle(ArgumentsDescriptor::New(arg_count))); |
| 1978 __ xorq(RCX, RCX); | 1974 __ xorq(RCX, RCX); |
| 1979 | 1975 |
| 1980 // Tail-call the function. | 1976 // Tail-call the function. |
| 1981 __ movq(RDI, FieldAddress(RAX, Function::instructions_offset())); | 1977 __ movq(RDI, FieldAddress(RAX, Function::instructions_offset())); |
| 1982 __ addq(RDI, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | 1978 __ addq(RDI, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 1983 __ jmp(RDI); | 1979 __ jmp(RDI); |
| 1984 } | 1980 } |
| 1985 | 1981 |
| 1986 | 1982 |
| 1987 // On stack: user tag (+1), return-address (+0). | 1983 // On stack: user tag (+1), return-address (+0). |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2013 __ LoadIsolate(RAX); | 2009 __ LoadIsolate(RAX); |
| 2014 __ movq(RAX, Address(RAX, Isolate::current_tag_offset())); | 2010 __ movq(RAX, Address(RAX, Isolate::current_tag_offset())); |
| 2015 __ ret(); | 2011 __ ret(); |
| 2016 } | 2012 } |
| 2017 | 2013 |
| 2018 #undef __ | 2014 #undef __ |
| 2019 | 2015 |
| 2020 } // namespace dart | 2016 } // namespace dart |
| 2021 | 2017 |
| 2022 #endif // defined TARGET_ARCH_X64 | 2018 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |