Chromium Code Reviews| 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 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 static_cast<int32_t>(MOV) << kOpcodeShift | | 298 static_cast<int32_t>(MOV) << kOpcodeShift | |
| 299 static_cast<int32_t>(rd) << kRdShift | | 299 static_cast<int32_t>(rd) << kRdShift | |
| 300 so.encoding() << kShiftRegisterShift | | 300 so.encoding() << kShiftRegisterShift | |
| 301 static_cast<int32_t>(opcode) << kShiftShift | | 301 static_cast<int32_t>(opcode) << kShiftShift | |
| 302 B4 | | 302 B4 | |
| 303 static_cast<int32_t>(rm); | 303 static_cast<int32_t>(rm); |
| 304 Emit(encoding); | 304 Emit(encoding); |
| 305 } | 305 } |
| 306 | 306 |
| 307 | 307 |
| 308 void Assembler::EmitBranch(Condition cond, Label* label, bool link) { | |
| 309 if (label->IsBound()) { | |
| 310 EmitType5(cond, label->Position() - buffer_.Size(), link); | |
| 311 } else { | |
| 312 int position = buffer_.Size(); | |
| 313 // Use the offset field of the branch instruction for linking the sites. | |
| 314 EmitType5(cond, label->position_, link); | |
| 315 label->LinkTo(position); | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 | |
| 320 void Assembler::and_(Register rd, Register rn, ShifterOperand so, | 308 void Assembler::and_(Register rd, Register rn, ShifterOperand so, |
| 321 Condition cond) { | 309 Condition cond) { |
| 322 EmitType01(cond, so.type(), AND, 0, rn, rd, so); | 310 EmitType01(cond, so.type(), AND, 0, rn, rd, so); |
| 323 } | 311 } |
| 324 | 312 |
| 325 | 313 |
| 326 void Assembler::eor(Register rd, Register rn, ShifterOperand so, | 314 void Assembler::eor(Register rd, Register rn, ShifterOperand so, |
| 327 Condition cond) { | 315 Condition cond) { |
| 328 EmitType01(cond, so.type(), EOR, 0, rn, rd, so); | 316 EmitType01(cond, so.type(), EOR, 0, rn, rd, so); |
| 329 } | 317 } |
| (...skipping 1388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1718 | 1706 |
| 1719 | 1707 |
| 1720 void Assembler::CompareClassId(Register object, | 1708 void Assembler::CompareClassId(Register object, |
| 1721 intptr_t class_id, | 1709 intptr_t class_id, |
| 1722 Register scratch) { | 1710 Register scratch) { |
| 1723 LoadClassId(scratch, object); | 1711 LoadClassId(scratch, object); |
| 1724 CompareImmediate(scratch, class_id); | 1712 CompareImmediate(scratch, class_id); |
| 1725 } | 1713 } |
| 1726 | 1714 |
| 1727 | 1715 |
| 1716 static bool CanEncodeBranchOffset(int32_t offset) { | |
| 1717 offset -= 8; | |
|
regis
2013/07/29 21:48:04
Opportunity for cleanup:
Use Instr::kPCReadOffset
zra
2013/08/01 15:15:58
Done.
| |
| 1718 ASSERT(Utils::IsAligned(offset, 4)); | |
| 1719 return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset); | |
| 1720 } | |
| 1721 | |
| 1722 | |
| 1723 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) { | |
| 1724 // The offset is off by 8 due to the way the ARM CPUs read PC. | |
| 1725 offset -= 8; | |
|
regis
2013/07/29 21:48:04
ditto
zra
2013/08/01 15:15:58
Done.
| |
| 1726 ASSERT(Utils::IsAligned(offset, 4)); | |
| 1727 ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset)); | |
| 1728 | |
| 1729 // Properly preserve only the bits supported in the instruction. | |
| 1730 offset >>= 2; | |
| 1731 offset &= kBranchOffsetMask; | |
| 1732 return (inst & ~kBranchOffsetMask) | offset; | |
| 1733 } | |
| 1734 | |
| 1735 | |
| 1736 int Assembler::DecodeBranchOffset(int32_t inst) { | |
| 1737 // Sign-extend, left-shift by 2, then add 8. | |
| 1738 return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8); | |
|
regis
2013/07/29 21:48:04
ditto
zra
2013/08/01 15:15:58
Done.
| |
| 1739 } | |
| 1740 | |
| 1741 | |
| 1742 static int32_t DecodeLoadImmediate(int32_t movt, int32_t movw) { | |
| 1743 int32_t offset = 0; | |
| 1744 offset |= (movt & 0xf0000) << 12; | |
| 1745 offset |= (movt & 0xfff) << 16; | |
| 1746 offset |= (movw & 0xf0000) >> 4; | |
| 1747 offset |= movw & 0xfff; | |
| 1748 return offset; | |
| 1749 } | |
| 1750 | |
| 1751 | |
| 1752 class PatchFarBranch : public AssemblerFixup { | |
| 1753 public: | |
| 1754 PatchFarBranch() {} | |
| 1755 | |
| 1756 void Process(const MemoryRegion& region, int position) { | |
| 1757 const int32_t movw = region.Load<int32_t>(position); | |
| 1758 const int32_t movt = region.Load<int32_t>(position + Instr::kInstrSize); | |
| 1759 const int32_t bx = region.Load<int32_t>(position + 2 * Instr::kInstrSize); | |
| 1760 | |
| 1761 if (((movt & 0xfff0f000) == 0xe340c000) && // movt TMP, high | |
|
regis
2013/07/29 21:48:04
For clarity, I would use the name IP instead of TM
zra
2013/08/01 15:15:58
Renamed all instances in this file.
| |
| 1762 ((movw & 0xfff0f000) == 0xe300c000)) { // movw TMP, low | |
| 1763 const int32_t offset = DecodeLoadImmediate(movt, movw); | |
| 1764 const int32_t dest = region.start() + offset; | |
| 1765 const uint16_t dest_high = Utils::High16Bits(dest); | |
| 1766 const uint16_t dest_low = Utils::Low16Bits(dest); | |
| 1767 const int32_t patched_movt = | |
| 1768 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); | |
| 1769 const int32_t patched_movw = | |
| 1770 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); | |
| 1771 | |
| 1772 region.Store<int32_t>(position, patched_movw); | |
| 1773 region.Store<int32_t>(position + Instr::kInstrSize, patched_movt); | |
| 1774 return; | |
| 1775 } | |
| 1776 | |
| 1777 // If the offset loading instructions aren't there, we must have replaced | |
| 1778 // the far branch with a near one, and so these instructions should be NOPs. | |
| 1779 ASSERT((movt == Instr::kNopInstruction) && | |
| 1780 (bx == Instr::kNopInstruction)); | |
| 1781 } | |
| 1782 }; | |
| 1783 | |
| 1784 | |
| 1785 void Assembler::EmitFarBranch(Condition cond, int32_t offset, bool link) { | |
| 1786 const uint16_t low = Utils::Low16Bits(offset); | |
| 1787 const uint16_t high = Utils::High16Bits(offset); | |
| 1788 buffer_.EmitFixup(new PatchFarBranch()); | |
| 1789 movw(TMP, low); | |
| 1790 movt(TMP, high); | |
| 1791 if (link) { | |
| 1792 blx(TMP, cond); | |
| 1793 } else { | |
| 1794 bx(TMP, cond); | |
| 1795 } | |
| 1796 } | |
| 1797 | |
| 1798 | |
| 1799 void Assembler::EmitBranch(Condition cond, Label* label, bool link) { | |
| 1800 if (label->IsBound()) { | |
| 1801 const int32_t dest = label->Position() - buffer_.Size(); | |
| 1802 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { | |
| 1803 EmitFarBranch(cond, label->Position(), link); | |
| 1804 } else { | |
| 1805 EmitType5(cond, dest, link); | |
| 1806 } | |
| 1807 } else { | |
| 1808 const int position = buffer_.Size(); | |
| 1809 if (FLAG_use_far_branches) { | |
| 1810 const int32_t dest = label->position_; | |
| 1811 EmitFarBranch(cond, dest, link); | |
| 1812 } else { | |
| 1813 // Use the offset field of the branch instruction for linking the sites. | |
| 1814 EmitType5(cond, label->position_, link); | |
| 1815 } | |
| 1816 label->LinkTo(position); | |
| 1817 } | |
| 1818 } | |
| 1819 | |
| 1820 | |
| 1728 void Assembler::Bind(Label* label) { | 1821 void Assembler::Bind(Label* label) { |
| 1729 ASSERT(!label->IsBound()); | 1822 ASSERT(!label->IsBound()); |
| 1730 int bound_pc = buffer_.Size(); | 1823 int bound_pc = buffer_.Size(); |
| 1731 while (label->IsLinked()) { | 1824 while (label->IsLinked()) { |
| 1732 int32_t position = label->Position(); | 1825 const int32_t position = label->Position(); |
| 1733 int32_t next = buffer_.Load<int32_t>(position); | 1826 int32_t dest = bound_pc - position; |
| 1734 int32_t encoded = Assembler::EncodeBranchOffset(bound_pc - position, next); | 1827 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { |
| 1735 buffer_.Store<int32_t>(position, encoded); | 1828 // Far branches are enabled and we can't encode the branch offset. |
| 1736 label->position_ = Assembler::DecodeBranchOffset(next); | 1829 |
| 1830 // Grab instructions that load the offset. | |
| 1831 const int32_t movw = | |
| 1832 buffer_.Load<int32_t>(position); | |
| 1833 const int32_t movt = | |
| 1834 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | |
| 1835 | |
| 1836 // Change from relative to the branch to relative to the assembler buffer. | |
| 1837 dest = buffer_.Size(); | |
| 1838 const uint16_t dest_high = Utils::High16Bits(dest); | |
| 1839 const uint16_t dest_low = Utils::Low16Bits(dest); | |
| 1840 const int32_t patched_movt = | |
| 1841 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); | |
| 1842 const int32_t patched_movw = | |
| 1843 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); | |
| 1844 | |
| 1845 // Rewrite the instructions. | |
| 1846 buffer_.Store<int32_t>(position, patched_movw); | |
| 1847 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt); | |
| 1848 label->position_ = DecodeLoadImmediate(movt, movw); | |
| 1849 } else if (FLAG_use_far_branches && CanEncodeBranchOffset(dest)) { | |
| 1850 // Far branches are enabled, but we can encode the branch offset. | |
| 1851 | |
| 1852 // Grab instructions that load the offset, and the branch. | |
| 1853 const int32_t movw = | |
| 1854 buffer_.Load<int32_t>(position); | |
| 1855 const int32_t movt = | |
| 1856 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | |
| 1857 const int32_t branch = | |
| 1858 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); | |
| 1859 | |
| 1860 // Grab the branch condition, and encode the link bit. | |
| 1861 const int32_t cond = branch & 0xf0000000; | |
| 1862 const int32_t link = (branch & 0x20) << 19; | |
| 1863 | |
| 1864 // Encode the branch and the offset. | |
| 1865 const int32_t new_branch = cond | link | 0x0a000000; | |
| 1866 const int32_t encoded = EncodeBranchOffset(dest, new_branch); | |
| 1867 | |
| 1868 // Write the encoded branch instruction followed by two nops. | |
| 1869 buffer_.Store<int32_t>(position, encoded); | |
| 1870 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, | |
| 1871 Instr::kNopInstruction); | |
| 1872 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, | |
| 1873 Instr::kNopInstruction); | |
| 1874 | |
| 1875 label->position_ = DecodeLoadImmediate(movt, movw); | |
| 1876 } else { | |
| 1877 int32_t next = buffer_.Load<int32_t>(position); | |
| 1878 int32_t encoded = Assembler::EncodeBranchOffset(dest, next); | |
| 1879 buffer_.Store<int32_t>(position, encoded); | |
| 1880 label->position_ = Assembler::DecodeBranchOffset(next); | |
| 1881 } | |
| 1737 } | 1882 } |
| 1738 label->BindTo(bound_pc); | 1883 label->BindTo(bound_pc); |
| 1739 } | 1884 } |
| 1740 | 1885 |
| 1741 | 1886 |
| 1742 bool Address::CanHoldLoadOffset(OperandSize type, | 1887 bool Address::CanHoldLoadOffset(OperandSize type, |
| 1743 int32_t offset, | 1888 int32_t offset, |
| 1744 int32_t* offset_mask) { | 1889 int32_t* offset_mask) { |
| 1745 switch (type) { | 1890 switch (type) { |
| 1746 case kByte: | 1891 case kByte: |
| (...skipping 764 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2511 // 'unstop' and continue execution in the simulator or jump to the next | 2656 // 'unstop' and continue execution in the simulator or jump to the next |
| 2512 // instruction in gdb. | 2657 // instruction in gdb. |
| 2513 Label stop; | 2658 Label stop; |
| 2514 b(&stop); | 2659 b(&stop); |
| 2515 Emit(reinterpret_cast<int32_t>(message)); | 2660 Emit(reinterpret_cast<int32_t>(message)); |
| 2516 Bind(&stop); | 2661 Bind(&stop); |
| 2517 svc(kStopMessageSvcCode); | 2662 svc(kStopMessageSvcCode); |
| 2518 } | 2663 } |
| 2519 | 2664 |
| 2520 | 2665 |
| 2521 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) { | |
| 2522 // The offset is off by 8 due to the way the ARM CPUs read PC. | |
| 2523 offset -= 8; | |
| 2524 ASSERT(Utils::IsAligned(offset, 4)); | |
| 2525 ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset)); | |
| 2526 | |
| 2527 // Properly preserve only the bits supported in the instruction. | |
| 2528 offset >>= 2; | |
| 2529 offset &= kBranchOffsetMask; | |
| 2530 return (inst & ~kBranchOffsetMask) | offset; | |
| 2531 } | |
| 2532 | |
| 2533 | |
| 2534 int Assembler::DecodeBranchOffset(int32_t inst) { | |
| 2535 // Sign-extend, left-shift by 2, then add 8. | |
| 2536 return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8); | |
| 2537 } | |
| 2538 | |
| 2539 | |
| 2540 int32_t Assembler::AddObject(const Object& obj) { | 2666 int32_t Assembler::AddObject(const Object& obj) { |
| 2541 ASSERT(obj.IsNotTemporaryScopedHandle()); | 2667 ASSERT(obj.IsNotTemporaryScopedHandle()); |
| 2542 ASSERT(obj.IsOld()); | 2668 ASSERT(obj.IsOld()); |
| 2543 if (object_pool_.IsNull()) { | 2669 if (object_pool_.IsNull()) { |
| 2544 // The object pool cannot be used in the vm isolate. | 2670 // The object pool cannot be used in the vm isolate. |
| 2545 ASSERT(Isolate::Current() != Dart::vm_isolate()); | 2671 ASSERT(Isolate::Current() != Dart::vm_isolate()); |
| 2546 object_pool_ = GrowableObjectArray::New(Heap::kOld); | 2672 object_pool_ = GrowableObjectArray::New(Heap::kOld); |
| 2547 } | 2673 } |
| 2548 for (int i = 0; i < object_pool_.Length(); i++) { | 2674 for (int i = 0; i < object_pool_.Length(); i++) { |
| 2549 if (object_pool_.At(i) == obj.raw()) { | 2675 if (object_pool_.At(i) == obj.raw()) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2594 | 2720 |
| 2595 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 2721 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
| 2596 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 2722 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
| 2597 return fpu_reg_names[reg]; | 2723 return fpu_reg_names[reg]; |
| 2598 } | 2724 } |
| 2599 | 2725 |
| 2600 } // namespace dart | 2726 } // namespace dart |
| 2601 | 2727 |
| 2602 #endif // defined TARGET_ARCH_ARM | 2728 #endif // defined TARGET_ARCH_ARM |
| 2603 | 2729 |
| OLD | NEW |