| 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 #include "vm/simulator.h" | 9 #include "vm/simulator.h" |
| 10 #include "vm/runtime_entry.h" | 10 #include "vm/runtime_entry.h" |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 type << kTypeShift | | 164 type << kTypeShift | |
| 165 static_cast<int32_t>(opcode) << kOpcodeShift | | 165 static_cast<int32_t>(opcode) << kOpcodeShift | |
| 166 set_cc << kSShift | | 166 set_cc << kSShift | |
| 167 static_cast<int32_t>(rn) << kRnShift | | 167 static_cast<int32_t>(rn) << kRnShift | |
| 168 static_cast<int32_t>(rd) << kRdShift | | 168 static_cast<int32_t>(rd) << kRdShift | |
| 169 so.encoding(); | 169 so.encoding(); |
| 170 Emit(encoding); | 170 Emit(encoding); |
| 171 } | 171 } |
| 172 | 172 |
| 173 | 173 |
| 174 void Assembler::EmitType5(Condition cond, int offset, bool link) { | 174 void Assembler::EmitType5(Condition cond, int32_t offset, bool link) { |
| 175 ASSERT(cond != kNoCondition); | 175 ASSERT(cond != kNoCondition); |
| 176 int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | | 176 int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | |
| 177 5 << kTypeShift | | 177 5 << kTypeShift | |
| 178 (link ? 1 : 0) << kLinkShift; | 178 (link ? 1 : 0) << kLinkShift; |
| 179 Emit(Assembler::EncodeBranchOffset(offset, encoding)); | 179 Emit(Assembler::EncodeBranchOffset(offset, encoding)); |
| 180 } | 180 } |
| 181 | 181 |
| 182 | 182 |
| 183 void Assembler::EmitMemOp(Condition cond, | 183 void Assembler::EmitMemOp(Condition cond, |
| 184 bool load, | 184 bool load, |
| (...skipping 1043 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 | 1228 |
| 1229 | 1229 |
| 1230 void Assembler::Drop(intptr_t stack_elements) { | 1230 void Assembler::Drop(intptr_t stack_elements) { |
| 1231 ASSERT(stack_elements >= 0); | 1231 ASSERT(stack_elements >= 0); |
| 1232 if (stack_elements > 0) { | 1232 if (stack_elements > 0) { |
| 1233 AddImmediate(SP, SP, stack_elements * kWordSize); | 1233 AddImmediate(SP, SP, stack_elements * kWordSize); |
| 1234 } | 1234 } |
| 1235 } | 1235 } |
| 1236 | 1236 |
| 1237 | 1237 |
| 1238 // Uses a code sequence that can easily be decoded. |
| 1239 void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { |
| 1240 ASSERT(rd != PP); |
| 1241 int32_t offset_mask = 0; |
| 1242 if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) { |
| 1243 ldr(rd, Address(PP, offset)); |
| 1244 } else { |
| 1245 int32_t offset_hi = offset & ~offset_mask; // signed |
| 1246 uint32_t offset_lo = offset & offset_mask; // unsigned |
| 1247 // Inline a simplified version of AddImmediate(rd, PP, offset_hi). |
| 1248 ShifterOperand shifter_op; |
| 1249 if (ShifterOperand::CanHold(offset_hi, &shifter_op)) { |
| 1250 add(rd, PP, shifter_op); |
| 1251 } else { |
| 1252 movw(rd, Utils::Low16Bits(offset_hi)); |
| 1253 const uint16_t value_high = Utils::High16Bits(offset_hi); |
| 1254 if (value_high != 0) { |
| 1255 movt(rd, value_high); |
| 1256 } |
| 1257 add(rd, PP, ShifterOperand(LR)); |
| 1258 } |
| 1259 ldr(rd, Address(rd, offset_lo)); |
| 1260 } |
| 1261 } |
| 1262 |
| 1263 |
| 1238 void Assembler::LoadObject(Register rd, const Object& object) { | 1264 void Assembler::LoadObject(Register rd, const Object& object) { |
| 1239 if (object.IsNull() || | 1265 if (object.IsNull() || |
| 1240 object.IsSmi() || | 1266 object.IsSmi() || |
| 1241 (object.raw() == Bool::True().raw()) || | 1267 (object.raw() == Bool::True().raw()) || |
| 1242 (object.raw() == Bool::False().raw())) { | 1268 (object.raw() == Bool::False().raw())) { |
| 1243 // This object is never relocated; do not use object pool. | 1269 // This object is never relocated; do not use object pool. |
| 1244 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw())); | 1270 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw())); |
| 1245 return; | 1271 return; |
| 1246 } | 1272 } |
| 1247 const int32_t offset = | 1273 const int32_t offset = |
| 1248 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; | 1274 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; |
| 1249 int32_t offset_mask = 0; | 1275 LoadWordFromPoolOffset(rd, offset); |
| 1250 if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) { | |
| 1251 ldr(rd, Address(PP, offset)); | |
| 1252 } else { | |
| 1253 int32_t offset_hi = offset & ~offset_mask; // signed | |
| 1254 uint32_t offset_lo = offset & offset_mask; // unsigned | |
| 1255 AddImmediate(rd, PP, offset_hi); | |
| 1256 ldr(rd, Address(rd, offset_lo)); | |
| 1257 } | |
| 1258 } | 1276 } |
| 1259 | 1277 |
| 1260 | 1278 |
| 1261 void Assembler::PushObject(const Object& object) { | 1279 void Assembler::PushObject(const Object& object) { |
| 1262 LoadObject(IP, object); | 1280 LoadObject(IP, object); |
| 1263 Push(IP); | 1281 Push(IP); |
| 1264 } | 1282 } |
| 1265 | 1283 |
| 1266 | 1284 |
| 1267 void Assembler::Bind(Label* label) { | 1285 void Assembler::Bind(Label* label) { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1419 } | 1437 } |
| 1420 | 1438 |
| 1421 | 1439 |
| 1422 void Assembler::BranchLinkPatchable(const ExternalLabel* label) { | 1440 void Assembler::BranchLinkPatchable(const ExternalLabel* label) { |
| 1423 // Make sure that class CallPattern is able to patch the label referred | 1441 // Make sure that class CallPattern is able to patch the label referred |
| 1424 // to by this code sequence. | 1442 // to by this code sequence. |
| 1425 // For added code robustness, use 'blx lr' in a patchable sequence and | 1443 // For added code robustness, use 'blx lr' in a patchable sequence and |
| 1426 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). | 1444 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). |
| 1427 const int32_t offset = | 1445 const int32_t offset = |
| 1428 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; | 1446 Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag; |
| 1429 int32_t offset_mask = 0; | 1447 LoadWordFromPoolOffset(LR, offset); |
| 1430 if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) { | |
| 1431 ldr(LR, Address(PP, offset)); | |
| 1432 } else { | |
| 1433 int32_t offset_hi = offset & ~offset_mask; // signed | |
| 1434 uint32_t offset_lo = offset & offset_mask; // unsigned | |
| 1435 // Inline a simplified version of AddImmediate(LR, CP, offset_hi). | |
| 1436 ShifterOperand shifter_op; | |
| 1437 if (ShifterOperand::CanHold(offset_hi, &shifter_op)) { | |
| 1438 add(LR, PP, shifter_op); | |
| 1439 } else { | |
| 1440 movw(LR, Utils::Low16Bits(offset_hi)); | |
| 1441 const uint16_t value_high = Utils::High16Bits(offset_hi); | |
| 1442 if (value_high != 0) { | |
| 1443 movt(LR, value_high); | |
| 1444 } | |
| 1445 add(LR, PP, ShifterOperand(LR)); | |
| 1446 } | |
| 1447 ldr(LR, Address(LR, offset_lo)); | |
| 1448 } | |
| 1449 blx(LR); // Use blx instruction so that the return branch prediction works. | 1448 blx(LR); // Use blx instruction so that the return branch prediction works. |
| 1450 } | 1449 } |
| 1451 | 1450 |
| 1452 | 1451 |
| 1453 void Assembler::BranchLinkStore(const ExternalLabel* label, Address ad) { | 1452 void Assembler::BranchLinkStore(const ExternalLabel* label, Address ad) { |
| 1454 // TODO(regis): Revisit this code sequence. | 1453 // TODO(regis): Revisit this code sequence. |
| 1455 LoadImmediate(IP, label->address()); // Target address is never patched. | 1454 LoadImmediate(IP, label->address()); // Target address is never patched. |
| 1456 str(PC, ad); | 1455 str(PC, ad); |
| 1457 blx(IP); // Use blx instruction so that the return branch prediction works. | 1456 blx(IP); // Use blx instruction so that the return branch prediction works. |
| 1458 } | 1457 } |
| 1459 | 1458 |
| 1460 | 1459 |
| 1461 void Assembler::BranchLinkOffset(Register base, int offset) { | 1460 void Assembler::BranchLinkOffset(Register base, int32_t offset) { |
| 1462 ASSERT(base != PC); | 1461 ASSERT(base != PC); |
| 1463 ASSERT(base != IP); | 1462 ASSERT(base != IP); |
| 1464 int32_t offset_mask = 0; | 1463 LoadFromOffset(kLoadWord, IP, base, offset); |
| 1465 if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) { | |
| 1466 ldr(IP, Address(base, offset)); | |
| 1467 } else { | |
| 1468 int offset_hi = offset & ~offset_mask; | |
| 1469 int offset_lo = offset & offset_mask; | |
| 1470 ShifterOperand offset_hi_op; | |
| 1471 if (ShifterOperand::CanHold(offset_hi, &offset_hi_op)) { | |
| 1472 add(IP, base, offset_hi_op); | |
| 1473 ldr(IP, Address(IP, offset_lo)); | |
| 1474 } else { | |
| 1475 LoadImmediate(IP, offset_hi); | |
| 1476 add(IP, IP, ShifterOperand(base)); | |
| 1477 ldr(IP, Address(IP, offset_lo)); | |
| 1478 } | |
| 1479 } | |
| 1480 blx(IP); // Use blx instruction so that the return branch prediction works. | 1464 blx(IP); // Use blx instruction so that the return branch prediction works. |
| 1481 } | 1465 } |
| 1482 | 1466 |
| 1483 | 1467 |
| 1484 void Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { | 1468 void Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { |
| 1485 ShifterOperand shifter_op; | 1469 ShifterOperand shifter_op; |
| 1486 if (ShifterOperand::CanHold(value, &shifter_op)) { | 1470 if (ShifterOperand::CanHold(value, &shifter_op)) { |
| 1487 mov(rd, shifter_op, cond); | 1471 mov(rd, shifter_op, cond); |
| 1488 } else if (ShifterOperand::CanHold(~value, &shifter_op)) { | 1472 } else if (ShifterOperand::CanHold(~value, &shifter_op)) { |
| 1489 mvn(rd, shifter_op, cond); | 1473 mvn(rd, shifter_op, cond); |
| (...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1908 // 'unstop' and continue execution in the simulator or jump to the next | 1892 // 'unstop' and continue execution in the simulator or jump to the next |
| 1909 // instruction in gdb. | 1893 // instruction in gdb. |
| 1910 Label stop; | 1894 Label stop; |
| 1911 b(&stop); | 1895 b(&stop); |
| 1912 Emit(reinterpret_cast<int32_t>(message)); | 1896 Emit(reinterpret_cast<int32_t>(message)); |
| 1913 Bind(&stop); | 1897 Bind(&stop); |
| 1914 svc(kStopMessageSvcCode); | 1898 svc(kStopMessageSvcCode); |
| 1915 } | 1899 } |
| 1916 | 1900 |
| 1917 | 1901 |
| 1918 int32_t Assembler::EncodeBranchOffset(int offset, int32_t inst) { | 1902 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) { |
| 1919 // The offset is off by 8 due to the way the ARM CPUs read PC. | 1903 // The offset is off by 8 due to the way the ARM CPUs read PC. |
| 1920 offset -= 8; | 1904 offset -= 8; |
| 1921 ASSERT(Utils::IsAligned(offset, 4)); | 1905 ASSERT(Utils::IsAligned(offset, 4)); |
| 1922 ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset)); | 1906 ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset)); |
| 1923 | 1907 |
| 1924 // Properly preserve only the bits supported in the instruction. | 1908 // Properly preserve only the bits supported in the instruction. |
| 1925 offset >>= 2; | 1909 offset >>= 2; |
| 1926 offset &= kBranchOffsetMask; | 1910 offset &= kBranchOffsetMask; |
| 1927 return (inst & ~kBranchOffsetMask) | offset; | 1911 return (inst & ~kBranchOffsetMask) | offset; |
| 1928 } | 1912 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1963 // Do not reuse an existing entry, since each reference may be patched | 1947 // Do not reuse an existing entry, since each reference may be patched |
| 1964 // independently. | 1948 // independently. |
| 1965 object_pool_.Add(smi); | 1949 object_pool_.Add(smi); |
| 1966 return object_pool_.Length() - 1; | 1950 return object_pool_.Length() - 1; |
| 1967 } | 1951 } |
| 1968 | 1952 |
| 1969 } // namespace dart | 1953 } // namespace dart |
| 1970 | 1954 |
| 1971 #endif // defined TARGET_ARCH_ARM | 1955 #endif // defined TARGET_ARCH_ARM |
| 1972 | 1956 |
| OLD | NEW |