| 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 |