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/longjump.h" |
| 10 #include "vm/runtime_entry.h" |
9 #include "vm/simulator.h" | 11 #include "vm/simulator.h" |
10 #include "vm/runtime_entry.h" | |
11 #include "vm/stack_frame.h" | 12 #include "vm/stack_frame.h" |
12 #include "vm/stub_code.h" | 13 #include "vm/stub_code.h" |
13 | 14 |
14 // An extra check since we are assuming the existence of /proc/cpuinfo below. | 15 // An extra check since we are assuming the existence of /proc/cpuinfo below. |
15 #if !defined(USING_SIMULATOR) && !defined(__linux__) | 16 #if !defined(USING_SIMULATOR) && !defined(__linux__) |
16 #error ARM cross-compile only supported on Linux | 17 #error ARM cross-compile only supported on Linux |
17 #endif | 18 #endif |
18 | 19 |
19 namespace dart { | 20 namespace dart { |
20 | 21 |
(...skipping 1691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1712 | 1713 |
1713 void Assembler::CompareClassId(Register object, | 1714 void Assembler::CompareClassId(Register object, |
1714 intptr_t class_id, | 1715 intptr_t class_id, |
1715 Register scratch) { | 1716 Register scratch) { |
1716 LoadClassId(scratch, object); | 1717 LoadClassId(scratch, object); |
1717 CompareImmediate(scratch, class_id); | 1718 CompareImmediate(scratch, class_id); |
1718 } | 1719 } |
1719 | 1720 |
1720 | 1721 |
1721 static bool CanEncodeBranchOffset(int32_t offset) { | 1722 static bool CanEncodeBranchOffset(int32_t offset) { |
1722 offset -= Instr::kPCReadOffset; | |
1723 ASSERT(Utils::IsAligned(offset, 4)); | 1723 ASSERT(Utils::IsAligned(offset, 4)); |
1724 return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset); | 1724 return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset); |
1725 } | 1725 } |
1726 | 1726 |
1727 | 1727 |
1728 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) { | 1728 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) { |
1729 // The offset is off by 8 due to the way the ARM CPUs read PC. | 1729 // The offset is off by 8 due to the way the ARM CPUs read PC. |
1730 offset -= Instr::kPCReadOffset; | 1730 offset -= Instr::kPCReadOffset; |
1731 ASSERT(Utils::IsAligned(offset, 4)); | 1731 |
1732 ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset)); | 1732 if (!CanEncodeBranchOffset(offset)) { |
| 1733 ASSERT(!use_far_branches()); |
| 1734 const Error& error = Error::Handle(LanguageError::New( |
| 1735 String::Handle(String::New("Branch offset overflow")))); |
| 1736 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 1737 } |
1733 | 1738 |
1734 // Properly preserve only the bits supported in the instruction. | 1739 // Properly preserve only the bits supported in the instruction. |
1735 offset >>= 2; | 1740 offset >>= 2; |
1736 offset &= kBranchOffsetMask; | 1741 offset &= kBranchOffsetMask; |
1737 return (inst & ~kBranchOffsetMask) | offset; | 1742 return (inst & ~kBranchOffsetMask) | offset; |
1738 } | 1743 } |
1739 | 1744 |
1740 | 1745 |
1741 int Assembler::DecodeBranchOffset(int32_t inst) { | 1746 int Assembler::DecodeBranchOffset(int32_t inst) { |
1742 // Sign-extend, left-shift by 2, then add 8. | 1747 // Sign-extend, left-shift by 2, then add 8. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1797 blx(IP, cond); | 1802 blx(IP, cond); |
1798 } else { | 1803 } else { |
1799 bx(IP, cond); | 1804 bx(IP, cond); |
1800 } | 1805 } |
1801 } | 1806 } |
1802 | 1807 |
1803 | 1808 |
1804 void Assembler::EmitBranch(Condition cond, Label* label, bool link) { | 1809 void Assembler::EmitBranch(Condition cond, Label* label, bool link) { |
1805 if (label->IsBound()) { | 1810 if (label->IsBound()) { |
1806 const int32_t dest = label->Position() - buffer_.Size(); | 1811 const int32_t dest = label->Position() - buffer_.Size(); |
1807 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { | 1812 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
1808 EmitFarBranch(cond, label->Position(), link); | 1813 EmitFarBranch(cond, label->Position(), link); |
1809 } else { | 1814 } else { |
1810 EmitType5(cond, dest, link); | 1815 EmitType5(cond, dest, link); |
1811 } | 1816 } |
1812 } else { | 1817 } else { |
1813 const int position = buffer_.Size(); | 1818 const int position = buffer_.Size(); |
1814 if (FLAG_use_far_branches) { | 1819 if (use_far_branches()) { |
1815 const int32_t dest = label->position_; | 1820 const int32_t dest = label->position_; |
1816 EmitFarBranch(cond, dest, link); | 1821 EmitFarBranch(cond, dest, link); |
1817 } else { | 1822 } else { |
1818 // Use the offset field of the branch instruction for linking the sites. | 1823 // Use the offset field of the branch instruction for linking the sites. |
1819 EmitType5(cond, label->position_, link); | 1824 EmitType5(cond, label->position_, link); |
1820 } | 1825 } |
1821 label->LinkTo(position); | 1826 label->LinkTo(position); |
1822 } | 1827 } |
1823 } | 1828 } |
1824 | 1829 |
1825 | 1830 |
1826 void Assembler::Bind(Label* label) { | 1831 void Assembler::Bind(Label* label) { |
1827 ASSERT(!label->IsBound()); | 1832 ASSERT(!label->IsBound()); |
1828 int bound_pc = buffer_.Size(); | 1833 int bound_pc = buffer_.Size(); |
1829 while (label->IsLinked()) { | 1834 while (label->IsLinked()) { |
1830 const int32_t position = label->Position(); | 1835 const int32_t position = label->Position(); |
1831 int32_t dest = bound_pc - position; | 1836 int32_t dest = bound_pc - position; |
1832 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) { | 1837 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
1833 // Far branches are enabled and we can't encode the branch offset. | 1838 // Far branches are enabled and we can't encode the branch offset. |
1834 | 1839 |
1835 // Grab instructions that load the offset. | 1840 // Grab instructions that load the offset. |
1836 const int32_t movw = | 1841 const int32_t movw = |
1837 buffer_.Load<int32_t>(position); | 1842 buffer_.Load<int32_t>(position); |
1838 const int32_t movt = | 1843 const int32_t movt = |
1839 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | 1844 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
1840 | 1845 |
1841 // Change from relative to the branch to relative to the assembler buffer. | 1846 // Change from relative to the branch to relative to the assembler buffer. |
1842 dest = buffer_.Size(); | 1847 dest = buffer_.Size(); |
1843 const uint16_t dest_high = Utils::High16Bits(dest); | 1848 const uint16_t dest_high = Utils::High16Bits(dest); |
1844 const uint16_t dest_low = Utils::Low16Bits(dest); | 1849 const uint16_t dest_low = Utils::Low16Bits(dest); |
1845 const int32_t patched_movt = | 1850 const int32_t patched_movt = |
1846 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); | 1851 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); |
1847 const int32_t patched_movw = | 1852 const int32_t patched_movw = |
1848 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); | 1853 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); |
1849 | 1854 |
1850 // Rewrite the instructions. | 1855 // Rewrite the instructions. |
1851 buffer_.Store<int32_t>(position, patched_movw); | 1856 buffer_.Store<int32_t>(position, patched_movw); |
1852 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt); | 1857 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt); |
1853 label->position_ = DecodeLoadImmediate(movt, movw); | 1858 label->position_ = DecodeLoadImmediate(movt, movw); |
1854 } else if (FLAG_use_far_branches && CanEncodeBranchOffset(dest)) { | 1859 } else if (use_far_branches() && CanEncodeBranchOffset(dest)) { |
1855 // Far branches are enabled, but we can encode the branch offset. | 1860 // Far branches are enabled, but we can encode the branch offset. |
1856 | 1861 |
1857 // Grab instructions that load the offset, and the branch. | 1862 // Grab instructions that load the offset, and the branch. |
1858 const int32_t movw = | 1863 const int32_t movw = |
1859 buffer_.Load<int32_t>(position); | 1864 buffer_.Load<int32_t>(position); |
1860 const int32_t movt = | 1865 const int32_t movt = |
1861 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | 1866 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
1862 const int32_t branch = | 1867 const int32_t branch = |
1863 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); | 1868 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); |
1864 | 1869 |
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2725 | 2730 |
2726 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 2731 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
2727 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 2732 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
2728 return fpu_reg_names[reg]; | 2733 return fpu_reg_names[reg]; |
2729 } | 2734 } |
2730 | 2735 |
2731 } // namespace dart | 2736 } // namespace dart |
2732 | 2737 |
2733 #endif // defined TARGET_ARCH_ARM | 2738 #endif // defined TARGET_ARCH_ARM |
2734 | 2739 |
OLD | NEW |