| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 | 9 |
| 10 #include "vm/stub_code.h" |
| 11 |
| 10 namespace dart { | 12 namespace dart { |
| 11 | 13 |
| 12 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); | 14 // TODO(regis): Enable this flag after PrintStopMessage stub is implemented. |
| 15 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); |
| 13 | 16 |
| 14 | 17 |
| 15 // Instruction encoding bits. | 18 // Instruction encoding bits. |
| 16 enum { | 19 enum { |
| 17 H = 1 << 5, // halfword (or byte) | 20 H = 1 << 5, // halfword (or byte) |
| 18 L = 1 << 20, // load (or store) | 21 L = 1 << 20, // load (or store) |
| 19 S = 1 << 20, // set condition code (or leave unchanged) | 22 S = 1 << 20, // set condition code (or leave unchanged) |
| 20 W = 1 << 21, // writeback base register (or leave unchanged) | 23 W = 1 << 21, // writeback base register (or leave unchanged) |
| 21 A = 1 << 21, // accumulate in multiply instruction (or not) | 24 A = 1 << 21, // accumulate in multiply instruction (or not) |
| 22 B = 1 << 22, // unsigned byte (or word) | 25 B = 1 << 22, // unsigned byte (or word) |
| (...skipping 1006 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 Bind(&l); | 1032 Bind(&l); |
| 1030 } | 1033 } |
| 1031 | 1034 |
| 1032 | 1035 |
| 1033 void Assembler::LoadObject(Register rd, const Object& object) { | 1036 void Assembler::LoadObject(Register rd, const Object& object) { |
| 1034 // TODO(regis): If the object is never relocated (null, true, false, ...), | 1037 // TODO(regis): If the object is never relocated (null, true, false, ...), |
| 1035 // load as immediate. | 1038 // load as immediate. |
| 1036 const int32_t offset = | 1039 const int32_t offset = |
| 1037 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; | 1040 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; |
| 1038 if (Address::CanHoldLoadOffset(kLoadWord, offset)) { | 1041 if (Address::CanHoldLoadOffset(kLoadWord, offset)) { |
| 1039 ldr(rd, Address(CP, offset)); | 1042 ldr(rd, Address(PP, offset)); |
| 1040 } else { | 1043 } else { |
| 1041 int32_t offset12_hi = offset & ~kOffset12Mask; // signed | 1044 int32_t offset12_hi = offset & ~kOffset12Mask; // signed |
| 1042 uint32_t offset12_lo = offset & kOffset12Mask; // unsigned | 1045 uint32_t offset12_lo = offset & kOffset12Mask; // unsigned |
| 1043 AddConstant(rd, CP, offset12_hi); | 1046 AddConstant(rd, PP, offset12_hi); |
| 1044 ldr(rd, Address(rd, offset12_lo)); | 1047 ldr(rd, Address(rd, offset12_lo)); |
| 1045 } | 1048 } |
| 1046 } | 1049 } |
| 1047 | 1050 |
| 1048 | 1051 |
| 1049 void Assembler::Bind(Label* label) { | 1052 void Assembler::Bind(Label* label) { |
| 1050 ASSERT(!label->IsBound()); | 1053 ASSERT(!label->IsBound()); |
| 1051 int bound_pc = buffer_.Size(); | 1054 int bound_pc = buffer_.Size(); |
| 1052 while (label->IsLinked()) { | 1055 while (label->IsLinked()) { |
| 1053 int32_t position = label->Position(); | 1056 int32_t position = label->Position(); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 } | 1163 } |
| 1161 | 1164 |
| 1162 | 1165 |
| 1163 void Assembler::Branch(const ExternalLabel* label) { | 1166 void Assembler::Branch(const ExternalLabel* label) { |
| 1164 LoadImmediate(IP, label->address()); // Target address is never patched. | 1167 LoadImmediate(IP, label->address()); // Target address is never patched. |
| 1165 mov(PC, ShifterOperand(IP)); | 1168 mov(PC, ShifterOperand(IP)); |
| 1166 } | 1169 } |
| 1167 | 1170 |
| 1168 | 1171 |
| 1169 void Assembler::BranchLink(const ExternalLabel* label) { | 1172 void Assembler::BranchLink(const ExternalLabel* label) { |
| 1173 LoadImmediate(IP, label->address()); // Target address is never patched. |
| 1174 blx(IP); // Use blx instruction so that the return branch prediction works. |
| 1175 } |
| 1176 |
| 1177 |
| 1178 void Assembler::BranchLinkPatchable(const ExternalLabel* label) { |
| 1170 // TODO(regis): Make sure that CodePatcher is able to patch the label referred | 1179 // TODO(regis): Make sure that CodePatcher is able to patch the label referred |
| 1171 // to by this code sequence. | 1180 // to by this code sequence. |
| 1172 // For added code robustness, use 'blx lr' in a patchable sequence and | 1181 // For added code robustness, use 'blx lr' in a patchable sequence and |
| 1173 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). | 1182 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). |
| 1174 const int32_t offset = | 1183 const int32_t offset = |
| 1175 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; | 1184 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; |
| 1176 if (Address::CanHoldLoadOffset(kLoadWord, offset)) { | 1185 if (Address::CanHoldLoadOffset(kLoadWord, offset)) { |
| 1177 ldr(LR, Address(CP, offset)); | 1186 ldr(LR, Address(PP, offset)); |
| 1178 } else { | 1187 } else { |
| 1179 int32_t offset12_hi = offset & ~kOffset12Mask; // signed | 1188 int32_t offset12_hi = offset & ~kOffset12Mask; // signed |
| 1180 uint32_t offset12_lo = offset & kOffset12Mask; // unsigned | 1189 uint32_t offset12_lo = offset & kOffset12Mask; // unsigned |
| 1181 // Inline a simplified version of AddConstant(LR, CP, offset12_hi). | 1190 // Inline a simplified version of AddConstant(LR, CP, offset12_hi). |
| 1182 ShifterOperand shifter_op; | 1191 ShifterOperand shifter_op; |
| 1183 if (ShifterOperand::CanHold(offset12_hi, &shifter_op)) { | 1192 if (ShifterOperand::CanHold(offset12_hi, &shifter_op)) { |
| 1184 add(LR, CP, shifter_op); | 1193 add(LR, PP, shifter_op); |
| 1185 } else { | 1194 } else { |
| 1186 movw(LR, Utils::Low16Bits(offset12_hi)); | 1195 movw(LR, Utils::Low16Bits(offset12_hi)); |
| 1187 const uint16_t value_high = Utils::High16Bits(offset12_hi); | 1196 const uint16_t value_high = Utils::High16Bits(offset12_hi); |
| 1188 if (value_high != 0) { | 1197 if (value_high != 0) { |
| 1189 movt(LR, value_high); | 1198 movt(LR, value_high); |
| 1190 } | 1199 } |
| 1191 add(LR, CP, ShifterOperand(LR)); | 1200 add(LR, PP, ShifterOperand(LR)); |
| 1192 } | 1201 } |
| 1193 ldr(LR, Address(LR, offset12_lo)); | 1202 ldr(LR, Address(LR, offset12_lo)); |
| 1194 } | 1203 } |
| 1195 blx(LR); // Use blx instruction so that the return branch prediction works. | 1204 blx(LR); // Use blx instruction so that the return branch prediction works. |
| 1196 } | 1205 } |
| 1197 | 1206 |
| 1198 | 1207 |
| 1199 void Assembler::BranchLinkStore(const ExternalLabel* label, Address ad) { | 1208 void Assembler::BranchLinkStore(const ExternalLabel* label, Address ad) { |
| 1200 // TODO(regis): Revisit this code sequence. | 1209 // TODO(regis): Revisit this code sequence. |
| 1201 LoadImmediate(IP, label->address()); // Target address is never patched. | 1210 LoadImmediate(IP, label->address()); // Target address is never patched. |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1493 movt(IP, value_high, cond); | 1502 movt(IP, value_high, cond); |
| 1494 } | 1503 } |
| 1495 adc(rd, rn, ShifterOperand(IP), cond); | 1504 adc(rd, rn, ShifterOperand(IP), cond); |
| 1496 } | 1505 } |
| 1497 } | 1506 } |
| 1498 } | 1507 } |
| 1499 | 1508 |
| 1500 | 1509 |
| 1501 void Assembler::Stop(const char* message) { | 1510 void Assembler::Stop(const char* message) { |
| 1502 if (FLAG_print_stop_message) { | 1511 if (FLAG_print_stop_message) { |
| 1503 UNIMPLEMENTED(); // Emit call to StubCode::PrintStopMessage(). | 1512 PushList((1 << R0) | (1 << IP) | (1 << LR)); // Preserve R0, IP, LR. |
| 1513 LoadImmediate(R0, reinterpret_cast<int32_t>(message)); |
| 1514 // PrintStopMessage() preserves all registers. |
| 1515 BranchLink(&StubCode::PrintStopMessageLabel()); // Passing message in R0. |
| 1516 PopList((1 << R0) | (1 << IP) | (1 << LR)); // Restore R0, IP, LR. |
| 1504 } | 1517 } |
| 1505 // Emit the message address before the svc instruction, so that we can | 1518 // Emit the message address before the svc instruction, so that we can |
| 1506 // 'unstop' and continue execution in the simulator or jump to the next | 1519 // 'unstop' and continue execution in the simulator or jump to the next |
| 1507 // instruction in gdb. | 1520 // instruction in gdb. |
| 1508 Label stop; | 1521 Label stop; |
| 1509 b(&stop); | 1522 b(&stop); |
| 1510 Emit(reinterpret_cast<int32_t>(message)); | 1523 Emit(reinterpret_cast<int32_t>(message)); |
| 1511 Bind(&stop); | 1524 Bind(&stop); |
| 1512 svc(kStopMessageSvcCode); | 1525 svc(kStopMessageSvcCode); |
| 1513 } | 1526 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1526 } | 1539 } |
| 1527 | 1540 |
| 1528 | 1541 |
| 1529 int Assembler::DecodeBranchOffset(int32_t inst) { | 1542 int Assembler::DecodeBranchOffset(int32_t inst) { |
| 1530 // Sign-extend, left-shift by 2, then add 8. | 1543 // Sign-extend, left-shift by 2, then add 8. |
| 1531 return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8); | 1544 return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8); |
| 1532 } | 1545 } |
| 1533 | 1546 |
| 1534 | 1547 |
| 1535 int32_t Assembler::AddObject(const Object& obj) { | 1548 int32_t Assembler::AddObject(const Object& obj) { |
| 1549 if (object_pool_.IsNull()) { |
| 1550 // The object pool cannot be used in the vm isolate. |
| 1551 ASSERT(Isolate::Current() != Dart::vm_isolate()); |
| 1552 object_pool_ = GrowableObjectArray::New(); |
| 1553 } |
| 1536 for (int i = 0; i < object_pool_.Length(); i++) { | 1554 for (int i = 0; i < object_pool_.Length(); i++) { |
| 1537 if (object_pool_.At(i) == obj.raw()) { | 1555 if (object_pool_.At(i) == obj.raw()) { |
| 1538 return i; | 1556 return i; |
| 1539 } | 1557 } |
| 1540 } | 1558 } |
| 1541 object_pool_.Add(obj); | 1559 object_pool_.Add(obj); |
| 1542 return object_pool_.Length(); | 1560 return object_pool_.Length(); |
| 1543 } | 1561 } |
| 1544 | 1562 |
| 1545 | 1563 |
| 1546 int32_t Assembler::AddExternalLabel(const ExternalLabel* label) { | 1564 int32_t Assembler::AddExternalLabel(const ExternalLabel* label) { |
| 1547 const uword address = label->address(); | 1565 if (object_pool_.IsNull()) { |
| 1566 // The object pool cannot be used in the vm isolate. |
| 1567 ASSERT(Isolate::Current() != Dart::vm_isolate()); |
| 1568 object_pool_ = GrowableObjectArray::New(); |
| 1569 } |
| 1570 const word address = label->address(); |
| 1548 ASSERT(Utils::IsAligned(address, 4)); | 1571 ASSERT(Utils::IsAligned(address, 4)); |
| 1549 // The address is stored in the object array as a RawSmi. | 1572 // The address is stored in the object array as a RawSmi. |
| 1550 const Smi& smi = Smi::Handle(Smi::New(address >> kSmiTagShift)); | 1573 const Smi& smi = Smi::Handle(Smi::New(address >> kSmiTagShift)); |
| 1551 // Do not reuse an existing entry, since each reference may be patched | 1574 // Do not reuse an existing entry, since each reference may be patched |
| 1552 // independently. | 1575 // independently. |
| 1553 object_pool_.Add(smi); | 1576 object_pool_.Add(smi); |
| 1554 return object_pool_.Length(); | 1577 return object_pool_.Length(); |
| 1555 } | 1578 } |
| 1556 | 1579 |
| 1557 } // namespace dart | 1580 } // namespace dart |
| 1558 | 1581 |
| 1559 #endif // defined TARGET_ARCH_ARM | 1582 #endif // defined TARGET_ARCH_ARM |
| 1560 | 1583 |
| OLD | NEW |