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" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
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/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
(...skipping 1669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1680 // For the value we are only interested in the new/old bit and the tag bit. | 1680 // For the value we are only interested in the new/old bit and the tag bit. |
1681 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. | 1681 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. |
1682 and_(IP, value, Operand(value, LSL, kObjectAlignmentLog2 - 1)); | 1682 and_(IP, value, Operand(value, LSL, kObjectAlignmentLog2 - 1)); |
1683 // And the result with the negated space bit of the object. | 1683 // And the result with the negated space bit of the object. |
1684 bic(IP, IP, Operand(object)); | 1684 bic(IP, IP, Operand(object)); |
1685 tst(IP, Operand(kNewObjectAlignmentOffset)); | 1685 tst(IP, Operand(kNewObjectAlignmentOffset)); |
1686 b(no_update, EQ); | 1686 b(no_update, EQ); |
1687 } | 1687 } |
1688 | 1688 |
1689 | 1689 |
1690 Operand Assembler::GetVerifiedMemoryShadow() { | |
1691 Operand offset; | |
1692 if (!Operand::CanHold(VerifiedMemory::offset(), &offset)) { | |
1693 FATAL1("Offset 0x%" Px " not representable", VerifiedMemory::offset()); | |
1694 } | |
1695 return offset; | |
1696 } | |
1697 | |
1698 | |
1699 void Assembler::WriteShadowedField(Register base, | |
1700 intptr_t offset, | |
1701 Register value, | |
1702 Condition cond) { | |
1703 if (VerifiedMemory::enabled()) { | |
1704 ASSERT(base != value); | |
1705 Operand shadow(GetVerifiedMemoryShadow()); | |
1706 add(base, base, shadow, cond); | |
1707 str(value, Address(base, offset), cond); | |
1708 sub(base, base, shadow, cond); | |
1709 } | |
1710 str(value, Address(base, offset), cond); | |
1711 } | |
1712 | |
1713 | |
1714 void Assembler::WriteShadowedFieldPair(Register base, | |
1715 intptr_t offset, | |
1716 Register value_even, | |
1717 Register value_odd, | |
1718 Condition cond) { | |
1719 ASSERT(value_odd == value_even + 1); | |
1720 ASSERT(value_even % 2 == 0); | |
1721 if (VerifiedMemory::enabled()) { | |
1722 ASSERT(base != value_even); | |
1723 ASSERT(base != value_odd); | |
1724 Operand shadow(GetVerifiedMemoryShadow()); | |
1725 add(base, base, shadow, cond); | |
1726 strd(value_even, value_odd, base, offset, cond); | |
1727 sub(base, base, shadow, cond); | |
1728 } | |
1729 strd(value_even, value_odd, base, offset, cond); | |
1730 } | |
1731 | |
1732 | |
1733 Register UseRegister(Register reg, RegList* used) { | 1690 Register UseRegister(Register reg, RegList* used) { |
1734 ASSERT(reg != THR); | 1691 ASSERT(reg != THR); |
1735 ASSERT(reg != SP); | 1692 ASSERT(reg != SP); |
1736 ASSERT(reg != FP); | 1693 ASSERT(reg != FP); |
1737 ASSERT(reg != PC); | 1694 ASSERT(reg != PC); |
1738 ASSERT((*used & (1 << reg)) == 0); | 1695 ASSERT((*used & (1 << reg)) == 0); |
1739 *used |= (1 << reg); | 1696 *used |= (1 << reg); |
1740 return reg; | 1697 return reg; |
1741 } | 1698 } |
1742 | 1699 |
1743 | 1700 |
1744 Register AllocateRegister(RegList* used) { | 1701 Register AllocateRegister(RegList* used) { |
1745 const RegList free = ~*used; | 1702 const RegList free = ~*used; |
1746 return (free == 0) ? | 1703 return (free == 0) ? |
1747 kNoRegister : | 1704 kNoRegister : |
1748 UseRegister(static_cast<Register>(Utils::CountTrailingZeros(free)), used); | 1705 UseRegister(static_cast<Register>(Utils::CountTrailingZeros(free)), used); |
1749 } | 1706 } |
1750 | 1707 |
1751 | 1708 |
1752 void Assembler::VerifiedWrite(Register object, | |
1753 const Address& address, | |
1754 Register new_value, | |
1755 FieldContent old_content) { | |
1756 #if defined(DEBUG) | |
1757 ASSERT(address.mode() == Address::Offset || | |
1758 address.mode() == Address::NegOffset); | |
1759 // Allocate temporary registers (and check for register collisions). | |
1760 RegList used = 0; | |
1761 UseRegister(new_value, &used); | |
1762 Register base = UseRegister(address.rn(), &used); | |
1763 if ((object != base) && (object != kNoRegister)) { | |
1764 UseRegister(object, &used); | |
1765 } | |
1766 if (address.rm() != kNoRegister) { | |
1767 UseRegister(address.rm(), &used); | |
1768 } | |
1769 Register old_value = AllocateRegister(&used); | |
1770 Register temp = AllocateRegister(&used); | |
1771 PushList(used); | |
1772 ldr(old_value, address); | |
1773 // First check that 'old_value' contains 'old_content'. | |
1774 // Smi test. | |
1775 tst(old_value, Operand(kHeapObjectTag)); | |
1776 Label ok; | |
1777 switch (old_content) { | |
1778 case kOnlySmi: | |
1779 b(&ok, EQ); // Smi is OK. | |
1780 Stop("Expected smi."); | |
1781 break; | |
1782 case kHeapObjectOrSmi: | |
1783 b(&ok, EQ); // Smi is OK. | |
1784 // Non-smi case: Verify object pointer is word-aligned when untagged. | |
1785 COMPILE_ASSERT(kHeapObjectTag == 1); | |
1786 tst(old_value, Operand((kWordSize - 1) - kHeapObjectTag)); | |
1787 b(&ok, EQ); | |
1788 Stop("Expected heap object or Smi"); | |
1789 break; | |
1790 case kEmptyOrSmiOrNull: | |
1791 b(&ok, EQ); // Smi is OK. | |
1792 // Non-smi case: Check for the special zap word or null. | |
1793 // Note: Cannot use CompareImmediate, since IP may be in use. | |
1794 LoadImmediate(temp, Heap::kZap32Bits); | |
1795 cmp(old_value, Operand(temp)); | |
1796 b(&ok, EQ); | |
1797 LoadObject(temp, Object::null_object()); | |
1798 cmp(old_value, Operand(temp)); | |
1799 b(&ok, EQ); | |
1800 Stop("Expected zapped, Smi or null"); | |
1801 break; | |
1802 default: | |
1803 UNREACHABLE(); | |
1804 } | |
1805 Bind(&ok); | |
1806 if (VerifiedMemory::enabled()) { | |
1807 Operand shadow_offset(GetVerifiedMemoryShadow()); | |
1808 // Adjust the address to shadow. | |
1809 add(base, base, shadow_offset); | |
1810 ldr(temp, address); | |
1811 cmp(old_value, Operand(temp)); | |
1812 Label match; | |
1813 b(&match, EQ); | |
1814 Stop("Write barrier verification failed"); | |
1815 Bind(&match); | |
1816 // Write new value in shadow. | |
1817 str(new_value, address); | |
1818 // Restore original address. | |
1819 sub(base, base, shadow_offset); | |
1820 } | |
1821 str(new_value, address); | |
1822 PopList(used); | |
1823 #else | |
1824 str(new_value, address); | |
1825 #endif // DEBUG | |
1826 } | |
1827 | |
1828 | |
1829 void Assembler::StoreIntoObject(Register object, | 1709 void Assembler::StoreIntoObject(Register object, |
1830 const Address& dest, | 1710 const Address& dest, |
1831 Register value, | 1711 Register value, |
1832 bool can_value_be_smi) { | 1712 bool can_value_be_smi) { |
1833 ASSERT(object != value); | 1713 ASSERT(object != value); |
1834 VerifiedWrite(object, dest, value, kHeapObjectOrSmi); | 1714 str(value, dest); |
1835 Label done; | 1715 Label done; |
1836 if (can_value_be_smi) { | 1716 if (can_value_be_smi) { |
1837 StoreIntoObjectFilter(object, value, &done); | 1717 StoreIntoObjectFilter(object, value, &done); |
1838 } else { | 1718 } else { |
1839 StoreIntoObjectFilterNoSmi(object, value, &done); | 1719 StoreIntoObjectFilterNoSmi(object, value, &done); |
1840 } | 1720 } |
1841 // A store buffer update is required. | 1721 // A store buffer update is required. |
1842 RegList regs = (1 << CODE_REG) | (1 << LR); | 1722 RegList regs = (1 << CODE_REG) | (1 << LR); |
1843 if (value != R0) { | 1723 if (value != R0) { |
1844 regs |= (1 << R0); // Preserve R0. | 1724 regs |= (1 << R0); // Preserve R0. |
(...skipping 20 matching lines...) Expand all Loading... |
1865 object, FieldAddress(object, offset), value, can_value_be_smi); | 1745 object, FieldAddress(object, offset), value, can_value_be_smi); |
1866 } else { | 1746 } else { |
1867 AddImmediate(IP, object, offset - kHeapObjectTag); | 1747 AddImmediate(IP, object, offset - kHeapObjectTag); |
1868 StoreIntoObject(object, Address(IP), value, can_value_be_smi); | 1748 StoreIntoObject(object, Address(IP), value, can_value_be_smi); |
1869 } | 1749 } |
1870 } | 1750 } |
1871 | 1751 |
1872 | 1752 |
1873 void Assembler::StoreIntoObjectNoBarrier(Register object, | 1753 void Assembler::StoreIntoObjectNoBarrier(Register object, |
1874 const Address& dest, | 1754 const Address& dest, |
1875 Register value, | 1755 Register value) { |
1876 FieldContent old_content) { | 1756 str(value, dest); |
1877 VerifiedWrite(object, dest, value, old_content); | |
1878 #if defined(DEBUG) | 1757 #if defined(DEBUG) |
1879 Label done; | 1758 Label done; |
1880 StoreIntoObjectFilter(object, value, &done); | 1759 StoreIntoObjectFilter(object, value, &done); |
1881 Stop("Store buffer update is required"); | 1760 Stop("Store buffer update is required"); |
1882 Bind(&done); | 1761 Bind(&done); |
1883 #endif // defined(DEBUG) | 1762 #endif // defined(DEBUG) |
1884 // No store buffer update. | 1763 // No store buffer update. |
1885 } | 1764 } |
1886 | 1765 |
1887 | 1766 |
1888 void Assembler::StoreIntoObjectNoBarrierOffset(Register object, | |
1889 int32_t offset, | |
1890 Register value, | |
1891 FieldContent old_content) { | |
1892 int32_t ignored = 0; | |
1893 if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) { | |
1894 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, | |
1895 old_content); | |
1896 } else { | |
1897 AddImmediate(IP, object, offset - kHeapObjectTag); | |
1898 StoreIntoObjectNoBarrier(object, Address(IP), value, old_content); | |
1899 } | |
1900 } | |
1901 | |
1902 | |
1903 void Assembler::StoreIntoObjectNoBarrier(Register object, | 1767 void Assembler::StoreIntoObjectNoBarrier(Register object, |
1904 const Address& dest, | 1768 const Address& dest, |
1905 const Object& value, | 1769 const Object& value) { |
1906 FieldContent old_content) { | |
1907 ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal()); | 1770 ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal()); |
1908 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); | 1771 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); |
1909 ASSERT(value.IsSmi() || value.InVMHeap() || | 1772 ASSERT(value.IsSmi() || value.InVMHeap() || |
1910 (value.IsOld() && value.IsNotTemporaryScopedHandle())); | 1773 (value.IsOld() && value.IsNotTemporaryScopedHandle())); |
1911 // No store buffer update. | 1774 // No store buffer update. |
1912 LoadObject(IP, value); | 1775 LoadObject(IP, value); |
1913 VerifiedWrite(object, dest, IP, old_content); | 1776 str(IP, dest); |
1914 } | 1777 } |
1915 | 1778 |
1916 | 1779 |
1917 void Assembler::StoreIntoObjectNoBarrierOffset(Register object, | 1780 void Assembler::StoreIntoObjectNoBarrierOffset(Register object, |
1918 int32_t offset, | 1781 int32_t offset, |
1919 const Object& value, | 1782 Register value) { |
1920 FieldContent old_content) { | 1783 int32_t ignored = 0; |
| 1784 if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) { |
| 1785 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
| 1786 } else { |
| 1787 Register base = object == R9 ? R8 : R9; |
| 1788 Push(base); |
| 1789 AddImmediate(base, object, offset - kHeapObjectTag); |
| 1790 StoreIntoObjectNoBarrier(object, Address(base), value); |
| 1791 Pop(base); |
| 1792 } |
| 1793 } |
| 1794 |
| 1795 |
| 1796 void Assembler::StoreIntoObjectNoBarrierOffset(Register object, |
| 1797 int32_t offset, |
| 1798 const Object& value) { |
1921 ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal()); | 1799 ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal()); |
1922 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); | 1800 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); |
1923 int32_t ignored = 0; | 1801 int32_t ignored = 0; |
1924 if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) { | 1802 if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) { |
1925 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, | 1803 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
1926 old_content); | |
1927 } else { | 1804 } else { |
1928 Register base = object == R9 ? R8 : R9; | 1805 Register base = object == R9 ? R8 : R9; |
1929 Push(base); | 1806 Push(base); |
1930 AddImmediate(base, object, offset - kHeapObjectTag); | 1807 AddImmediate(base, object, offset - kHeapObjectTag); |
1931 StoreIntoObjectNoBarrier(object, Address(base), value, old_content); | 1808 StoreIntoObjectNoBarrier(object, Address(base), value); |
1932 Pop(base); | 1809 Pop(base); |
1933 } | 1810 } |
1934 } | 1811 } |
1935 | 1812 |
1936 | 1813 |
1937 void Assembler::InitializeFieldsNoBarrier(Register object, | 1814 void Assembler::InitializeFieldsNoBarrier(Register object, |
1938 Register begin, | 1815 Register begin, |
1939 Register end, | 1816 Register end, |
1940 Register value_even, | 1817 Register value_even, |
1941 Register value_odd) { | 1818 Register value_odd) { |
1942 ASSERT(value_odd == value_even + 1); | 1819 ASSERT(value_odd == value_even + 1); |
1943 Label init_loop; | 1820 Label init_loop; |
1944 Bind(&init_loop); | 1821 Bind(&init_loop); |
1945 AddImmediate(begin, 2 * kWordSize); | 1822 AddImmediate(begin, 2 * kWordSize); |
1946 cmp(begin, Operand(end)); | 1823 cmp(begin, Operand(end)); |
1947 WriteShadowedFieldPair(begin, -2 * kWordSize, value_even, value_odd, LS); | 1824 strd(value_even, value_odd, begin, -2 * kWordSize, LS); |
1948 b(&init_loop, CC); | 1825 b(&init_loop, CC); |
1949 WriteShadowedField(begin, -2 * kWordSize, value_even, HI); | 1826 str(value_even, Address(begin, -2 * kWordSize), HI); |
1950 #if defined(DEBUG) | 1827 #if defined(DEBUG) |
1951 Label done; | 1828 Label done; |
1952 StoreIntoObjectFilter(object, value_even, &done); | 1829 StoreIntoObjectFilter(object, value_even, &done); |
1953 StoreIntoObjectFilter(object, value_odd, &done); | 1830 StoreIntoObjectFilter(object, value_odd, &done); |
1954 Stop("Store buffer update is required"); | 1831 Stop("Store buffer update is required"); |
1955 Bind(&done); | 1832 Bind(&done); |
1956 #endif // defined(DEBUG) | 1833 #endif // defined(DEBUG) |
1957 // No store buffer update. | 1834 // No store buffer update. |
1958 } | 1835 } |
1959 | 1836 |
1960 | 1837 |
1961 void Assembler::InitializeFieldsNoBarrierUnrolled(Register object, | 1838 void Assembler::InitializeFieldsNoBarrierUnrolled(Register object, |
1962 Register base, | 1839 Register base, |
1963 intptr_t begin_offset, | 1840 intptr_t begin_offset, |
1964 intptr_t end_offset, | 1841 intptr_t end_offset, |
1965 Register value_even, | 1842 Register value_even, |
1966 Register value_odd) { | 1843 Register value_odd) { |
1967 ASSERT(value_odd == value_even + 1); | 1844 ASSERT(value_odd == value_even + 1); |
1968 intptr_t current_offset = begin_offset; | 1845 intptr_t current_offset = begin_offset; |
1969 while (current_offset + kWordSize < end_offset) { | 1846 while (current_offset + kWordSize < end_offset) { |
1970 WriteShadowedFieldPair(base, current_offset, value_even, value_odd); | 1847 strd(value_even, value_odd, base, current_offset); |
1971 current_offset += 2*kWordSize; | 1848 current_offset += 2*kWordSize; |
1972 } | 1849 } |
1973 while (current_offset < end_offset) { | 1850 while (current_offset < end_offset) { |
1974 WriteShadowedField(base, current_offset, value_even); | 1851 str(value_even, Address(base, current_offset)); |
1975 current_offset += kWordSize; | 1852 current_offset += kWordSize; |
1976 } | 1853 } |
1977 #if defined(DEBUG) | 1854 #if defined(DEBUG) |
1978 Label done; | 1855 Label done; |
1979 StoreIntoObjectFilter(object, value_even, &done); | 1856 StoreIntoObjectFilter(object, value_even, &done); |
1980 StoreIntoObjectFilter(object, value_odd, &done); | 1857 StoreIntoObjectFilter(object, value_odd, &done); |
1981 Stop("Store buffer update is required"); | 1858 Stop("Store buffer update is required"); |
1982 Bind(&done); | 1859 Bind(&done); |
1983 #endif // defined(DEBUG) | 1860 #endif // defined(DEBUG) |
1984 // No store buffer update. | 1861 // No store buffer update. |
1985 } | 1862 } |
1986 | 1863 |
1987 | 1864 |
1988 void Assembler::StoreIntoSmiField(const Address& dest, Register value) { | 1865 void Assembler::StoreIntoSmiField(const Address& dest, Register value) { |
1989 #if defined(DEBUG) | 1866 #if defined(DEBUG) |
1990 Label done; | 1867 Label done; |
1991 tst(value, Operand(kHeapObjectTag)); | 1868 tst(value, Operand(kHeapObjectTag)); |
1992 b(&done, EQ); | 1869 b(&done, EQ); |
1993 Stop("New value must be Smi."); | 1870 Stop("New value must be Smi."); |
1994 Bind(&done); | 1871 Bind(&done); |
1995 #endif // defined(DEBUG) | 1872 #endif // defined(DEBUG) |
1996 VerifiedWrite(kNoRegister, dest, value, kOnlySmi); | 1873 str(value, dest); |
1997 } | 1874 } |
1998 | 1875 |
1999 | 1876 |
2000 void Assembler::LoadClassId(Register result, Register object, Condition cond) { | 1877 void Assembler::LoadClassId(Register result, Register object, Condition cond) { |
2001 ASSERT(RawObject::kClassIdTagPos == 16); | 1878 ASSERT(RawObject::kClassIdTagPos == 16); |
2002 ASSERT(RawObject::kClassIdTagSize == 16); | 1879 ASSERT(RawObject::kClassIdTagSize == 16); |
2003 const intptr_t class_id_offset = Object::tags_offset() + | 1880 const intptr_t class_id_offset = Object::tags_offset() + |
2004 RawObject::kClassIdTagPos / kBitsPerByte; | 1881 RawObject::kClassIdTagPos / kBitsPerByte; |
2005 ldrh(result, FieldAddress(object, class_id_offset), cond); | 1882 ldrh(result, FieldAddress(object, class_id_offset), cond); |
2006 } | 1883 } |
(...skipping 1663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3670 | 3547 |
3671 | 3548 |
3672 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 3549 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
3673 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 3550 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
3674 return fpu_reg_names[reg]; | 3551 return fpu_reg_names[reg]; |
3675 } | 3552 } |
3676 | 3553 |
3677 } // namespace dart | 3554 } // namespace dart |
3678 | 3555 |
3679 #endif // defined TARGET_ARCH_ARM | 3556 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |