| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 // NOTE: R2 cannot be clobbered here as the caller relies on it being saved. | 669 // NOTE: R2 cannot be clobbered here as the caller relies on it being saved. |
| 670 // The newly allocated object is returned in R0. | 670 // The newly allocated object is returned in R0. |
| 671 void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler, | 671 void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler, |
| 672 uword* entry_patch_offset, uword* patch_code_pc_offset) { | 672 uword* entry_patch_offset, uword* patch_code_pc_offset) { |
| 673 *entry_patch_offset = assembler->CodeSize(); | 673 *entry_patch_offset = assembler->CodeSize(); |
| 674 Label slow_case; | 674 Label slow_case; |
| 675 // Compute the size to be allocated, it is based on the array length | 675 // Compute the size to be allocated, it is based on the array length |
| 676 // and is computed as: | 676 // and is computed as: |
| 677 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 677 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 678 // Assert that length is a Smi. | 678 // Assert that length is a Smi. |
| 679 __ tsti(R2, kSmiTagMask); | 679 __ tsti(R2, Immediate(kSmiTagMask)); |
| 680 if (FLAG_use_slow_path) { | 680 if (FLAG_use_slow_path) { |
| 681 __ b(&slow_case); | 681 __ b(&slow_case); |
| 682 } else { | 682 } else { |
| 683 __ b(&slow_case, NE); | 683 __ b(&slow_case, NE); |
| 684 } | 684 } |
| 685 __ cmp(R2, Operand(0)); | 685 __ cmp(R2, Operand(0)); |
| 686 __ b(&slow_case, LT); | 686 __ b(&slow_case, LT); |
| 687 | 687 |
| 688 Isolate* isolate = Isolate::Current(); | 688 Isolate* isolate = Isolate::Current(); |
| 689 Heap* heap = isolate->heap(); | 689 Heap* heap = isolate->heap(); |
| 690 const intptr_t cid = kArrayCid; | 690 const intptr_t cid = kArrayCid; |
| 691 Heap::Space space = heap->SpaceForAllocation(cid); | 691 Heap::Space space = heap->SpaceForAllocation(cid); |
| 692 const uword top_address = heap->TopAddress(space); | 692 const uword top_address = heap->TopAddress(space); |
| 693 __ LoadImmediate(R8, top_address, kNoPP); | 693 __ LoadImmediate(R8, top_address, kNoPP); |
| 694 const uword end_address = heap->EndAddress(space); | 694 const uword end_address = heap->EndAddress(space); |
| 695 ASSERT(top_address < end_address); | 695 ASSERT(top_address < end_address); |
| 696 const uword top_offset = 0; | 696 const uword top_offset = 0; |
| 697 const uword end_offset = end_address - top_address; | 697 const uword end_offset = end_address - top_address; |
| 698 | 698 |
| 699 // Calculate and align allocation size. | 699 // Calculate and align allocation size. |
| 700 // Load new object start and calculate next object start. | 700 // Load new object start and calculate next object start. |
| 701 // R1: array element type. | 701 // R1: array element type. |
| 702 // R2: array length as Smi. | 702 // R2: array length as Smi. |
| 703 // R8: points to new space object. | 703 // R8: points to new space object. |
| 704 __ LoadFromOffset(R0, R8, top_offset, kNoPP); | 704 __ LoadFromOffset(R0, R8, top_offset, kNoPP); |
| 705 intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; | 705 intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 706 __ LoadImmediate(R3, fixed_size, kNoPP); | 706 __ LoadImmediate(R3, fixed_size, kNoPP); |
| 707 __ add(R3, R3, Operand(R2, LSL, 2)); // R2 is Smi. | 707 __ add(R3, R3, Operand(R2, LSL, 2)); // R2 is Smi. |
| 708 ASSERT(kSmiTagShift == 1); | 708 ASSERT(kSmiTagShift == 1); |
| 709 __ andi(R3, R3, ~(kObjectAlignment - 1)); | 709 __ andi(R3, R3, Immediate(~(kObjectAlignment - 1))); |
| 710 __ adds(R7, R3, Operand(R0)); | 710 __ adds(R7, R3, Operand(R0)); |
| 711 __ b(&slow_case, VS); | 711 __ b(&slow_case, VS); |
| 712 | 712 |
| 713 // Check if the allocation fits into the remaining space. | 713 // Check if the allocation fits into the remaining space. |
| 714 // R0: potential new object start. | 714 // R0: potential new object start. |
| 715 // R1: array element type. | 715 // R1: array element type. |
| 716 // R2: array length as Smi. | 716 // R2: array length as Smi. |
| 717 // R3: array size. | 717 // R3: array size. |
| 718 // R7: potential next object start. | 718 // R7: potential next object start. |
| 719 // R8: points to new space object. | 719 // R8: points to new space object. |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 992 void StubCode::GenerateAllocateContextStub(Assembler* assembler) { | 992 void StubCode::GenerateAllocateContextStub(Assembler* assembler) { |
| 993 if (FLAG_inline_alloc) { | 993 if (FLAG_inline_alloc) { |
| 994 Label slow_case; | 994 Label slow_case; |
| 995 Heap* heap = Isolate::Current()->heap(); | 995 Heap* heap = Isolate::Current()->heap(); |
| 996 // First compute the rounded instance size. | 996 // First compute the rounded instance size. |
| 997 // R1: number of context variables. | 997 // R1: number of context variables. |
| 998 intptr_t fixed_size = sizeof(RawContext) + kObjectAlignment - 1; | 998 intptr_t fixed_size = sizeof(RawContext) + kObjectAlignment - 1; |
| 999 __ LoadImmediate(R2, fixed_size, kNoPP); | 999 __ LoadImmediate(R2, fixed_size, kNoPP); |
| 1000 __ add(R2, R2, Operand(R1, LSL, 3)); | 1000 __ add(R2, R2, Operand(R1, LSL, 3)); |
| 1001 ASSERT(kSmiTagShift == 1); | 1001 ASSERT(kSmiTagShift == 1); |
| 1002 __ andi(R2, R2, ~(kObjectAlignment - 1)); | 1002 __ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); |
| 1003 | 1003 |
| 1004 // Now allocate the object. | 1004 // Now allocate the object. |
| 1005 // R1: number of context variables. | 1005 // R1: number of context variables. |
| 1006 // R2: object size. | 1006 // R2: object size. |
| 1007 const intptr_t cid = kContextCid; | 1007 const intptr_t cid = kContextCid; |
| 1008 Heap::Space space = heap->SpaceForAllocation(cid); | 1008 Heap::Space space = heap->SpaceForAllocation(cid); |
| 1009 __ LoadImmediate(R5, heap->TopAddress(space), kNoPP); | 1009 __ LoadImmediate(R5, heap->TopAddress(space), kNoPP); |
| 1010 __ ldr(R0, Address(R5)); | 1010 __ ldr(R0, Address(R5)); |
| 1011 __ add(R3, R2, Operand(R0)); | 1011 __ add(R3, R2, Operand(R0)); |
| 1012 // Check if the allocation fits into the remaining space. | 1012 // Check if the allocation fits into the remaining space. |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1110 DECLARE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, Isolate* isolate); | 1110 DECLARE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, Isolate* isolate); |
| 1111 | 1111 |
| 1112 // Helper stub to implement Assembler::StoreIntoObject. | 1112 // Helper stub to implement Assembler::StoreIntoObject. |
| 1113 // Input parameters: | 1113 // Input parameters: |
| 1114 // R0: Address being stored | 1114 // R0: Address being stored |
| 1115 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { | 1115 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { |
| 1116 Label add_to_buffer; | 1116 Label add_to_buffer; |
| 1117 // Check whether this object has already been remembered. Skip adding to the | 1117 // Check whether this object has already been remembered. Skip adding to the |
| 1118 // store buffer if the object is in the store buffer already. | 1118 // store buffer if the object is in the store buffer already. |
| 1119 __ LoadFieldFromOffset(TMP, R0, Object::tags_offset(), kNoPP); | 1119 __ LoadFieldFromOffset(TMP, R0, Object::tags_offset(), kNoPP); |
| 1120 __ tsti(TMP, 1 << RawObject::kRememberedBit); | 1120 __ tsti(TMP, Immediate(1 << RawObject::kRememberedBit)); |
| 1121 __ b(&add_to_buffer, EQ); | 1121 __ b(&add_to_buffer, EQ); |
| 1122 __ ret(); | 1122 __ ret(); |
| 1123 | 1123 |
| 1124 __ Bind(&add_to_buffer); | 1124 __ Bind(&add_to_buffer); |
| 1125 // Save values being destroyed. | 1125 // Save values being destroyed. |
| 1126 __ Push(R1); | 1126 __ Push(R1); |
| 1127 __ Push(R2); | 1127 __ Push(R2); |
| 1128 __ Push(R3); | 1128 __ Push(R3); |
| 1129 | 1129 |
| 1130 __ orri(R2, TMP, 1 << RawObject::kRememberedBit); | 1130 __ orri(R2, TMP, Immediate(1 << RawObject::kRememberedBit)); |
| 1131 __ StoreFieldToOffset(R2, R0, Object::tags_offset(), kNoPP); | 1131 __ StoreFieldToOffset(R2, R0, Object::tags_offset(), kNoPP); |
| 1132 | 1132 |
| 1133 // Load the isolate. | 1133 // Load the isolate. |
| 1134 // Spilled: R1, R2, R3. | 1134 // Spilled: R1, R2, R3. |
| 1135 // R0: address being stored. | 1135 // R0: address being stored. |
| 1136 __ LoadIsolate(R1, kNoPP); | 1136 __ LoadIsolate(R1, kNoPP); |
| 1137 | 1137 |
| 1138 // Load the StoreBuffer block out of the isolate. Then load top_ out of the | 1138 // Load the StoreBuffer block out of the isolate. Then load top_ out of the |
| 1139 // StoreBufferBlock and add the address to the pointers_. | 1139 // StoreBufferBlock and add the address to the pointers_. |
| 1140 // R1: isolate. | 1140 // R1: isolate. |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1386 Token::Kind kind, | 1386 Token::Kind kind, |
| 1387 intptr_t num_args, | 1387 intptr_t num_args, |
| 1388 Label* not_smi_or_overflow) { | 1388 Label* not_smi_or_overflow) { |
| 1389 if (FLAG_throw_on_javascript_int_overflow) { | 1389 if (FLAG_throw_on_javascript_int_overflow) { |
| 1390 // The overflow check is more complex than implemented below. | 1390 // The overflow check is more complex than implemented below. |
| 1391 return; | 1391 return; |
| 1392 } | 1392 } |
| 1393 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Right. | 1393 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Right. |
| 1394 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Left. | 1394 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Left. |
| 1395 __ orr(TMP, R0, Operand(R1)); | 1395 __ orr(TMP, R0, Operand(R1)); |
| 1396 __ tsti(TMP, kSmiTagMask); | 1396 __ tsti(TMP, Immediate(kSmiTagMask)); |
| 1397 __ b(not_smi_or_overflow, NE); | 1397 __ b(not_smi_or_overflow, NE); |
| 1398 switch (kind) { | 1398 switch (kind) { |
| 1399 case Token::kADD: { | 1399 case Token::kADD: { |
| 1400 __ adds(R0, R1, Operand(R0)); // Adds. | 1400 __ adds(R0, R1, Operand(R0)); // Adds. |
| 1401 __ b(not_smi_or_overflow, VS); // Branch if overflow. | 1401 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| 1402 break; | 1402 break; |
| 1403 } | 1403 } |
| 1404 case Token::kSUB: { | 1404 case Token::kSUB: { |
| 1405 __ subs(R0, R1, Operand(R0)); // Subtract. | 1405 __ subs(R0, R1, Operand(R0)); // Subtract. |
| 1406 __ b(not_smi_or_overflow, VS); // Branch if overflow. | 1406 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1463 const RuntimeEntry& handle_ic_miss, | 1463 const RuntimeEntry& handle_ic_miss, |
| 1464 Token::Kind kind) { | 1464 Token::Kind kind) { |
| 1465 ASSERT(num_args > 0); | 1465 ASSERT(num_args > 0); |
| 1466 #if defined(DEBUG) | 1466 #if defined(DEBUG) |
| 1467 { Label ok; | 1467 { Label ok; |
| 1468 // Check that the IC data array has NumArgsTested() == num_args. | 1468 // Check that the IC data array has NumArgsTested() == num_args. |
| 1469 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1469 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1470 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1470 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| 1471 kNoPP, kUnsignedWord); | 1471 kNoPP, kUnsignedWord); |
| 1472 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1472 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1473 __ andi(R6, R6, ICData::NumArgsTestedMask()); | 1473 __ andi(R6, R6, Immediate(ICData::NumArgsTestedMask())); |
| 1474 __ CompareImmediate(R6, num_args, kNoPP); | 1474 __ CompareImmediate(R6, num_args, kNoPP); |
| 1475 __ b(&ok, EQ); | 1475 __ b(&ok, EQ); |
| 1476 __ Stop("Incorrect stub for IC data"); | 1476 __ Stop("Incorrect stub for IC data"); |
| 1477 __ Bind(&ok); | 1477 __ Bind(&ok); |
| 1478 } | 1478 } |
| 1479 #endif // DEBUG | 1479 #endif // DEBUG |
| 1480 | 1480 |
| 1481 // Check single stepping. | 1481 // Check single stepping. |
| 1482 Label stepping, done_stepping; | 1482 Label stepping, done_stepping; |
| 1483 __ LoadIsolate(R6, kNoPP); | 1483 __ LoadIsolate(R6, kNoPP); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1695 | 1695 |
| 1696 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1696 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1697 GenerateUsageCounterIncrement(assembler, R6); | 1697 GenerateUsageCounterIncrement(assembler, R6); |
| 1698 #if defined(DEBUG) | 1698 #if defined(DEBUG) |
| 1699 { Label ok; | 1699 { Label ok; |
| 1700 // Check that the IC data array has NumArgsTested() == 0. | 1700 // Check that the IC data array has NumArgsTested() == 0. |
| 1701 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1701 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1702 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1702 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| 1703 kNoPP, kUnsignedWord); | 1703 kNoPP, kUnsignedWord); |
| 1704 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1704 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1705 __ andi(R6, R6, ICData::NumArgsTestedMask()); | 1705 __ andi(R6, R6, Immediate(ICData::NumArgsTestedMask())); |
| 1706 __ CompareImmediate(R6, 0, kNoPP); | 1706 __ CompareImmediate(R6, 0, kNoPP); |
| 1707 __ b(&ok, EQ); | 1707 __ b(&ok, EQ); |
| 1708 __ Stop("Incorrect IC data for unoptimized static call"); | 1708 __ Stop("Incorrect IC data for unoptimized static call"); |
| 1709 __ Bind(&ok); | 1709 __ Bind(&ok); |
| 1710 } | 1710 } |
| 1711 #endif // DEBUG | 1711 #endif // DEBUG |
| 1712 | 1712 |
| 1713 // Check single stepping. | 1713 // Check single stepping. |
| 1714 Label stepping, done_stepping; | 1714 Label stepping, done_stepping; |
| 1715 __ LoadIsolate(R6, kNoPP); | 1715 __ LoadIsolate(R6, kNoPP); |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2027 // Return Zero condition flag set if equal. | 2027 // Return Zero condition flag set if equal. |
| 2028 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint | 2028 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint |
| 2029 // cannot contain a value that fits in Mint or Smi. | 2029 // cannot contain a value that fits in Mint or Smi. |
| 2030 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler, | 2030 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler, |
| 2031 const Register left, | 2031 const Register left, |
| 2032 const Register right, | 2032 const Register right, |
| 2033 const Register unused1, | 2033 const Register unused1, |
| 2034 const Register unused2) { | 2034 const Register unused2) { |
| 2035 Label reference_compare, done, check_mint, check_bigint; | 2035 Label reference_compare, done, check_mint, check_bigint; |
| 2036 // If any of the arguments is Smi do reference compare. | 2036 // If any of the arguments is Smi do reference compare. |
| 2037 __ tsti(left, kSmiTagMask); | 2037 __ tsti(left, Immediate(kSmiTagMask)); |
| 2038 __ b(&reference_compare, EQ); | 2038 __ b(&reference_compare, EQ); |
| 2039 __ tsti(right, kSmiTagMask); | 2039 __ tsti(right, Immediate(kSmiTagMask)); |
| 2040 __ b(&reference_compare, EQ); | 2040 __ b(&reference_compare, EQ); |
| 2041 | 2041 |
| 2042 // Value compare for two doubles. | 2042 // Value compare for two doubles. |
| 2043 __ CompareClassId(left, kDoubleCid, kNoPP); | 2043 __ CompareClassId(left, kDoubleCid, kNoPP); |
| 2044 __ b(&check_mint, NE); | 2044 __ b(&check_mint, NE); |
| 2045 __ CompareClassId(right, kDoubleCid, kNoPP); | 2045 __ CompareClassId(right, kDoubleCid, kNoPP); |
| 2046 __ b(&done, NE); | 2046 __ b(&done, NE); |
| 2047 | 2047 |
| 2048 // Double values bitwise compare. | 2048 // Double values bitwise compare. |
| 2049 __ LoadFieldFromOffset(left, left, Double::value_offset(), kNoPP); | 2049 __ LoadFieldFromOffset(left, left, Double::value_offset(), kNoPP); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2124 const Register right = R0; | 2124 const Register right = R0; |
| 2125 __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP); | 2125 __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP); |
| 2126 __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP); | 2126 __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP); |
| 2127 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2127 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 2128 __ ret(); | 2128 __ ret(); |
| 2129 } | 2129 } |
| 2130 | 2130 |
| 2131 } // namespace dart | 2131 } // namespace dart |
| 2132 | 2132 |
| 2133 #endif // defined TARGET_ARCH_ARM64 | 2133 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |